Skip to content

Latest commit

 

History

History
290 lines (225 loc) · 11.3 KB

File metadata and controls

290 lines (225 loc) · 11.3 KB

Implementation Notes: Issue #92 - Real Token Deployment

Summary

Replaced the simulated token deployment handler in DeployForm.tsx with a complete, production-grade Soroban token deployment flow that constructs transactions, simulates them, requests wallet signatures, broadcasts to the network, and provides user feedback.

What Changed

Files Created

  1. frontend/app/hooks/useDeployToken.ts (new)

    • Custom React hook encapsulating the 4-step deployment flow
    • Handles: transaction building, simulation, wallet signing, broadcasting, and polling
    • Includes initialization of the deployed contract with form parameters
    • Comprehensive error handling with typed error responses
  2. .env.example (new)

    • Documents all required environment variables for deployment
    • Includes instructions for obtaining the WASM hash
  3. IMPLEMENTATION_NOTES.md (this file)

    • Implementation documentation and validation steps

Files Modified

  1. frontend/app/deploy/DeployForm.tsx
    • Replaced simulated onSubmit handler with real deployment logic
    • Added useRouter for navigation to dashboard after successful deployment
    • Added useDeployToken hook integration
    • Enhanced error handling with type-specific error messages
    • Preserved all existing form validation and UI behavior

Transaction Flow

The implementation follows a 6-step deployment process:

Step 1: Validation

  • Verify wallet is connected
  • Verify WASM hash is configured
  • Validate all form data (handled by existing Zod schema)

Step 2: Build Deployment Transaction

  • Load source account from RPC to get current sequence number
  • Create createCustomContract operation with:
    • Deployer address (connected wallet)
    • Pre-uploaded WASM hash (from environment variable)
    • Random 32-byte salt for unique contract address
  • Build transaction with TransactionBuilder

Step 3: Simulate Deployment

  • Call rpc.simulateTransaction() on the deployment transaction
  • Check for simulation errors using StellarSdk.rpc.Api.isSimulationError()
  • Assemble transaction with simulation results (footprint, auth, fees)

Step 4: Sign Deployment Transaction

  • Request signature from Freighter wallet via signTransaction()
  • Detect and handle user rejection gracefully
  • Handle wallet disconnection and other wallet errors

Step 5: Broadcast and Poll Deployment

  • Send transaction via rpc.sendTransaction()
  • Poll rpc.getTransaction() every 2 seconds (max 30 attempts = 60 seconds)
  • Extract deployed contract ID from successful transaction result

Step 6: Initialize Contract

  • Build initialize() call with form parameters:
    • admin: adminAddress from form
    • decimal: decimals from form (note: contract uses singular)
    • name: token name
    • symbol: token symbol
    • initial_supply: initialSupply from form
    • max_supply: maxSupply from form (optional, uses ScVoid if not provided)
  • Simulate, sign, broadcast, and poll initialization transaction
  • Return contract ID and transaction hash on success

Environment Variables Required

All variables must be prefixed with NEXT_PUBLIC_ to be accessible in the browser:

Variable Required Default Description
NEXT_PUBLIC_SOROBAN_RPC_URL No https://soroban-testnet.stellar.org Soroban RPC endpoint
NEXT_PUBLIC_HORIZON_URL No https://horizon-testnet.stellar.org Horizon API endpoint
NEXT_PUBLIC_NETWORK_PASSPHRASE No Test SDF Network ; September 2015 Network passphrase
NEXT_PUBLIC_TOKEN_WASM_HASH Yes None Pre-uploaded token contract WASM hash

Obtaining the WASM Hash

The token contract WASM must be uploaded to the network before the frontend can deploy contracts:

# Build the contract
cd contracts
soroban contract build

# Upload WASM to testnet (requires funded account)
soroban contract upload \
  --wasm target/wasm32-unknown-unknown/release/soroban_token.wasm \
  --network testnet \
  --source <your-identity-or-secret-key>

# Copy the returned hash to .env.local
echo "NEXT_PUBLIC_TOKEN_WASM_HASH=<hash-from-upload>" >> frontend/.env.local

Error Handling

The implementation handles all failure modes with user-friendly messages:

Error Type Trigger User Message
validation Wallet not connected or WASM hash missing Clear validation message
simulation Transaction simulation fails "Simulation error: [details]"
wallet User rejects signature "Transaction signature was rejected. Please try again."
wallet Wallet disconnected or other error "Wallet signing failed: [details]"
broadcast Transaction submission fails "Broadcast error: [details]"
timeout Polling exceeds 60 seconds Message with transaction hash for manual lookup

Security Considerations

No private keys handled - All signing delegated to Freighter wallet extension
Simulation before signing - Every transaction is simulated before requesting signature
No secrets in browser bundle - All environment variables are intentionally public (RPC URLs, WASM hash)
User confirmation required - Freighter prompts user to review and approve each transaction
Error sanitization - Raw RPC errors are wrapped in user-friendly messages

Testing Performed

Type Checking

cd frontend
npx tsc --noEmit
# ✓ No type errors

Linting

cd frontend
npx eslint app/hooks/useDeployToken.ts app/deploy/DeployForm.tsx
# ✓ No errors or warnings

Build

cd frontend
npm run build
# ✓ Compiled successfully

Manual Integration Test (Testnet)

Prerequisites:

  1. Freighter wallet installed and connected to testnet
  2. Testnet account funded via Friendbot
  3. Token WASM uploaded and hash configured in .env.local

Test Steps:

  1. Start development server: npm run dev
  2. Navigate to /deploy
  3. Connect Freighter wallet
  4. Fill in form:
    • Name: "Test Token"
    • Symbol: "TEST"
    • Decimals: 7
    • Initial Supply: 1000000
    • Max Supply: 10000000
    • Admin Address: (connected wallet address)
  5. Click "Deploy Token"
  6. Approve deployment transaction in Freighter
  7. Wait for deployment confirmation
  8. Approve initialization transaction in Freighter
  9. Wait for initialization confirmation
  10. Verify redirect to /dashboard/[contractId]
  11. Verify contract ID and transaction hash displayed

Expected Results:

  • ✓ Deployment transaction simulated successfully
  • ✓ Freighter prompts for signature (deployment)
  • ✓ Deployment transaction broadcast and confirmed
  • ✓ Freighter prompts for signature (initialization)
  • ✓ Initialization transaction broadcast and confirmed
  • ✓ Success message displays contract ID and transaction hash
  • ✓ Redirect to dashboard page
  • ✓ No console errors

Negative Test Cases:

  1. Wallet rejection: Click "Reject" in Freighter → Error message displayed, form remains usable
  2. Invalid form data: Submit with missing fields → Validation blocks submission
  3. Wallet disconnection: Disconnect wallet before submission → Validation error displayed

Out-of-Scope Findings

During reconnaissance, the following items were identified but are out of scope for this issue:

  1. No test framework configured - The project has no Jest, Vitest, or other test setup in the frontend. Tests cannot be written until a framework is configured.
  2. No CI/CD pipeline - No GitHub Actions workflows or other CI configuration found. All checks were run locally.
  3. No existing transaction tests - No patterns to follow for testing transaction construction, simulation, or broadcast.
  4. Alert-based error display - The codebase uses alert() for user feedback. A toast notification library would improve UX but is out of scope.

Recommendations for Follow-Up Issues

  1. Issue: Set up frontend test framework - Configure Jest or Vitest with React Testing Library
  2. Issue: Add CI/CD pipeline - Create GitHub Actions workflow for type-check, lint, build, and test
  3. Issue: Implement toast notifications - Replace alert() with a proper toast library (e.g., react-hot-toast)
  4. Issue: Add transaction history - Store deployed contract IDs in local storage or database
  5. Issue: Add deployment progress indicator - Show step-by-step progress (simulating, signing, broadcasting, initializing)
  6. Issue: Add contract verification - After deployment, verify contract is initialized correctly by reading its state

Bundle Size Impact

The implementation adds the following to the client bundle:

  • useDeployToken hook: ~15 KB (minified)
  • No new dependencies (uses existing @stellar/stellar-sdk)

Total bundle size increase: ~15 KB (negligible impact)

Commit Message

feat(deploy): implement real token deployment transaction submission (#92)

Replace simulated deployment handler with production-grade Soroban token
deployment flow. Implements 6-step process: validation, transaction
building, simulation, wallet signing, broadcasting, and contract
initialization.

- Add useDeployToken hook with complete deployment logic
- Update DeployForm to use real deployment instead of simulation
- Add comprehensive error handling for all failure modes
- Add .env.example documenting required environment variables
- Preserve all existing form validation and UI behavior

Closes #92

Branch Name

feat/issue-92-real-token-deployment

Validation Checklist

  • Type checking passes (npx tsc --noEmit)
  • Linting passes (npx eslint)
  • Production build succeeds (npm run build)
  • No existing tests broken (no tests exist)
  • All form validation preserved
  • Loading state managed correctly
  • Error handling covers all failure modes
  • No secrets exposed in browser bundle
  • No private keys handled by application
  • Simulation performed before every signature request
  • Environment variables documented in .env.example

Known Limitations

  1. WASM hash must be pre-uploaded - The frontend cannot upload WASM files (too large for browser bundle). Contracts must be uploaded via CLI first.
  2. No transaction history - Deployed contract IDs are not persisted. Users must bookmark or save the contract ID manually.
  3. Alert-based feedback - Uses browser alert() for error messages. A toast library would improve UX.
  4. No retry mechanism - If a transaction fails, users must restart the entire deployment process.
  5. No gas estimation - Uses default base fee. Could be improved with dynamic fee estimation.

Post-Deployment Verification

After deploying a token on testnet, verify the deployment by:

  1. Check contract on Stellar Expert:

    https://stellar.expert/explorer/testnet/contract/[CONTRACT_ID]
    
  2. Query contract state via RPC:

    soroban contract invoke \
      --id [CONTRACT_ID] \
      --network testnet \
      -- name
  3. Verify in dashboard: Navigate to /dashboard/[CONTRACT_ID] and confirm:

    • Token name, symbol, decimals display correctly
    • Total supply matches initial supply
    • Admin address matches form input

Support

For questions or issues with this implementation:

  1. Check the Stellar Soroban documentation
  2. Review the Freighter API documentation
  3. Open a GitHub Discussion or comment on issue #92