Skip to main content

How Swaps Resolve

This page explains the complete lifecycle of a swap, from input to output.

Direct swap flow

When you call swap(fromStablecoin, toStablecoin, amount, queueIfUnavailable):

1. Transfer fromStablecoin from user to contract

2. Process fromStablecoin queue (FIFO)
→ Fill waiting positions with incoming tokens
→ Add remainder to reserves

3. Check toStablecoin reserves

4a. If reserves >= amount:
→ Transfer toStablecoin to user
→ Done (instant swap)

4b. If reserves < amount:
→ If some reserves available (partial fill):
- Transfer available reserves to user
- Remaining either queued (if queueIfUnavailable = true) or minted as DLRS (if false)
→ If zero reserves:
- Queue entire amount (if queueIfUnavailable = true)
- REVERT (if queueIfUnavailable = false)

Note: If you want "all or nothing" behavior, use queueIfUnavailable = false and rely on the revert when reserves are insufficient. The revert is the authoritative check—while you can call getReserve() first, race conditions mean reserves may change between your check and the swap.

Example: Full instant swap

State before:
USDC reserves: 10,000
USDT reserves: 5,000
USDC queue: empty

User swaps 3,000 USDC → USDT:

1. 3,000 USDC transferred to contract
2. USDC queue is empty, so 3,000 added to reserves
3. USDT reserves (5,000) >= 3,000 ✓
4. 3,000 USDT transferred to user

State after:
USDC reserves: 13,000
USDT reserves: 2,000

Example: Partial fill with queue

State before:
USDC reserves: 10,000
USDT reserves: 1,000
USDT queue: empty

User swaps 3,000 USDC → USDT (queueIfUnavailable = true):

1. 3,000 USDC transferred to contract
2. USDC queue empty, 3,000 added to reserves
3. USDT reserves (1,000) < 3,000
4. 1,000 USDT transferred to user (partial)
5. 2,000 DLRS worth queued for USDT

State after:
USDC reserves: 13,000
USDT reserves: 0
USDT queue: [User: 2,000]

Example: Queue gets filled

Continuing from above:

State:
USDT reserves: 0
USDT queue: [User: 2,000]

Someone deposits 5,000 USDT:

1. 5,000 USDT transferred to contract
2. Process USDT queue:
→ User receives 2,000 USDT (position filled, removed)
3. Remaining 3,000 added to reserves

State after:
USDT reserves: 3,000
USDT queue: empty

Aggregator flow

The swapExactInput function follows a simpler flow:

1. Check deadline hasn't passed
2. Check toStablecoin reserves >= amountIn
→ If not, REVERT (no partial fills, no queue)
3. Transfer fromStablecoin from user
4. Process fromStablecoin queue
5. Add remainder to fromStablecoin reserves
6. Deduct from toStablecoin reserves
7. Transfer toStablecoin to recipient

This guarantees: either full execution or complete failure. No intermediate states.