Lendasat LogoLendasat Docs

Swap State Machine

Understanding swap states and transitions

LendaSwap swaps progress through a well-defined state machine that ensures atomicity and proper handling of all scenarios.

State Overview
                    ┌──────────┐
                    │ Pending  │
                    └────┬─────┘

              ┌──────────┴──────────┐
              │                     │
    (User pays BTC)      (Timeout: 30 min)
              │                     │
              ▼                     ▼
      ┌───────────────┐      ┌──────────┐
      │ ClientFunded  │      │ Expired  │
      └───────┬───────┘      └──────────┘

    ┌─────────┴──────────┐
    │                    │
(Service creates HTLC) (User refunds)
    │                    │
    ▼                    ▼
┌───────────────┐ ┌─────────────────┐
│ ServerFunded  │ │ ClientRefunded  │
└───────┬───────┘ └─────────────────┘

┌───────┴────────┐
│                │
(User claims)  (HTLC timeout)
│                │
▼                ▼
┌────────────┐ ┌──────────────────────────┐
│    Done    │ │ ClientFundedServerRefunded│
└────────────┘ └──────────────────────────┘

States Explained
CodeStateDescriptionAction Required
0PendingSwap created, waiting for BTC paymentPay BTC
1ClientFundedBTC received, preparing HTLCWait
2ServerFundedHTLC created on Polygon, ready to claimClaim now
3DoneSwap complete, user received USDCNone
4Expired30 min timeout, no payment receivedNone
5ClientRefundedUser refunded before HTLC createdNone
6ClientFundedServerRefundedHTLC timeout, service reclaimed WBTCRefund

Flow Examples
Success Flow (~95% of swaps)
Pending → ClientFunded → ServerFunded → Done
  1. User creates swap request
  2. User pays BTC via Lightning (~10 seconds)
  3. Service creates HTLC on Polygon (~30 seconds)
  4. User claims USDC (gasless) (~10 seconds)

Total time: ~50 seconds

Timeout Flow (~2% of swaps)
Pending → ClientFunded → ServerFunded → ClientFundedServerRefunded

User paid BTC but didn't claim USDC within 10 minutes. Service refunds WBTC, user keeps BTC.

Expiration Flow (~5% of swaps)
Pending → Expired

User never paid within 30 minutes. No funds locked.


Transition Rules
FromEventToProbability
PendingUser pays BTCClientFunded~95%
Pending30 min timeoutExpired~5%
ClientFundedHTLC createdServerFunded~99%
ServerFundedUser claimsDone~98%
ServerFundedHTLC timeoutClientFundedServerRefunded~2%

Handling Each Status
const swaps = await client.listAllSwaps();

for (const stored of swaps) {
  const swap = stored.response;
  switch (swap.status) {
    case "serverfunded":
      console.log(`Swap ${stored.swapId}: Ready to claim!`);
      await client.claim(stored.swapId);
      break;
    case "clientfundedserverrefunded":
      console.log(`Swap ${stored.swapId}: Needs refund`);
      break;
    case "clientredeemed":
      console.log(`Swap ${stored.swapId}: Complete`);
      break;
    default:
      console.log(`Swap ${stored.swapId}: ${swap.status}`);
  }
}

On-chain BTC → Arkade States
1. Pending      - Swap created, waiting for BTC
2. ClientFunded - BTC received, waiting for confirmations
3. ServerFunded - Arkade VHTLC created, ready to claim
4. Done         - VTXOs claimed successfully

Best Practices
  1. Monitor Pending swaps - Prompt users to pay before timeout
  2. Auto-claim ServerFunded - Claim immediately when ready
  3. Handle timeouts gracefully - Show appropriate messages for expired swaps
  4. Track terminal states - Clean up UI for completed/expired swaps

Resources