Skip to content

Latest commit

 

History

History
155 lines (120 loc) · 3.9 KB

File metadata and controls

155 lines (120 loc) · 3.9 KB

Soroban Escrow Integration Summary

What Was Done

Wired the Soroban escrow contract into the production payout path. Prize pools are now settled atomically via smart contract.

Problem

  • Contract existed but was never called
  • Payout service used direct hot-wallet transfers (custodial)
  • No wrapper library for contract interaction
  • Deployment scripts missing

Solution

  • Created EscrowClient wrapper for clean contract interaction
  • Modified payout service to use escrow settlement
  • Added deployment scripts
  • Implemented graceful fallback to direct transfers

Key Changes

1. EscrowClient Wrapper

File: packages/stellar/src/escrow.ts

Clean API for contract interaction:

  • initialize() — Set up contract for challenge
  • deposit() — Brand funds pool
  • settle() — Atomic distribution to winners
  • refund() — Return funds if cancelled
  • getBalance() — View balance
  • isSettled() — View settlement status

2. Payout Service Integration

File: apps/api/src/services/payout.ts

Modified to:

  1. Check if SOROBAN_CONTRACT_ID configured
  2. If yes → use EscrowClient.settle() (atomic)
  3. If no → fall back to direct transfers
  4. Log which path used

3. Deployment Script

File: contracts/contracts/escrow/Makefile

Added:

  • make deploy-testnet — Deploy to testnet
  • make deploy-mainnet — Deploy to mainnet

4. Configuration

File: .env.example

Added:

  • SOROBAN_CONTRACT_ID — Contract ID after deployment
  • STELLAR_RPC_URL — Soroban RPC endpoint

5. ADR Documentation

File: docs/adr/003-escrow-implementation.md

Documents decision, rationale, deployment, monitoring

6. Integration Tests

File: packages/stellar/src/escrow.test.ts

Tests wrapper and contract interaction

How It Works

Challenge ends
    ↓
Payout worker processes
    ↓
If SOROBAN_CONTRACT_ID set:
  → Use EscrowClient.settle()
  → Atomic distribution
  → Non-custodial
    ↓
Else:
  → Fall back to direct transfers
  → Custodial (temporary)
    ↓
Update challenge to "settled"

Decision: Escrow for All Challenges

Not just high-value challenges because:

  • Simplifies logic (one path)
  • Maximizes non-custodial benefits
  • Atomic settlement prevents bugs
  • Graceful fallback if needed

Graceful Fallback

If contract has issues:

  1. Unset SOROBAN_CONTRACT_ID
  2. Payout service automatically uses direct transfers
  3. No code changes needed
  4. Payouts continue normally

Deployment Path

Testnet (Immediate)

  1. Deploy: make deploy-testnet
  2. Set SOROBAN_CONTRACT_ID in test env
  3. Run integration tests
  4. Monitor 24h

Staging (1 week)

  1. Deploy to staging Soroban
  2. Set SOROBAN_CONTRACT_ID
  3. Run full E2E test
  4. Monitor 7 days

Mainnet (After Audit)

  1. External security audit
  2. Deploy: make deploy-mainnet
  3. Set SOROBAN_CONTRACT_ID
  4. Canary: one challenge
  5. Monitor 24h
  6. Gradual rollout

Benefits

Non-custodial: Platform never holds funds
Atomic: All-or-nothing distribution
Auditable: On-chain proof
Graceful: Works without contract
Testable: Can disable for testing

Acceptance Criteria Met

✅ ADR docs/adr/003-escrow-implementation.md
✅ packages/stellar/src/escrow.ts wrapper
✅ Payout worker uses settle()
✅ Deployment script: make deploy-testnet/mainnet
✅ Integration test: initialize, deposit, settle
✅ CONTRACT_ID env var documented

Files Modified

  • packages/stellar/src/escrow.ts — NEW
  • packages/stellar/src/escrow.test.ts — NEW
  • apps/api/src/services/payout.ts — Modified
  • contracts/contracts/escrow/Makefile — Modified
  • docs/adr/003-escrow-implementation.md — NEW
  • .env.example — Modified

Next Steps

  1. Deploy contract to testnet
  2. Set SOROBAN_CONTRACT_ID in test env
  3. Run integration tests
  4. Monitor payout service
  5. Schedule external audit
  6. Deploy to mainnet after audit