Swap Steps

A Sovereign Pool swap performs the following steps:

1. User initiates swap

  • Lock all state modifying functions in the pool.

  • Basic checks on _swapParams:

    • _swapParams.amountIn cannot be 0.

    • _swapParams.recipient must be non-zero.

    • _swapParams.swapTokenOut cannot be zero address nor input token.

    • In case the pool is meant to hold reserves (sovereignVault == address(this)), _swapParams.swapTokenOut must be either token0 or token1, meaning that only token0 ↔ token1 swaps are supported. Only if an external vault is specified (sovereignVault ≠ address(this)) then multi-hop swaps are allowed (where _swapParams.swapTokenOut could differ from token0 or token1).

2. Call Verifier Module

  • If _verifierModule is non-empty , the Verifier Module is called with the relevant input data. If invalid, it triggers a revert, otherwise, the swap continues and caches any return data from _verifierModule.

3. Call Swap Fee Module

  • If Swap Fee Module is set, it gets called with the relevant input data to return the swap fee (since we do not yet know how much tokenIn liquidity will be filled, this fee will be applied after calling getLiquidityQuote). If Swap Fee Module is not set, a constant and immutable pool fee will be applied. Alternatively, both can be ignored and fees can be designed into a Liquidity Module's internal pricing.

4. Call Liquidity Module

LM is called using getLiquidityQuote with all relevant inputs, including return data from Verifier Module if applicable, and returns the liquidity quote information.

5. Check Liquidity Quote Validity

Consistency checks for the liquidity quote are applied. The transaction reverts if one or more of the following are broken:

* LM cannot quote more tokenOut reserves than it has in the pool. Except in the case where the funds are not supplied from the pool itself (`sovereignVault ≠ address(this)`)
* LM’s quoted tokenOut amount to the user must be equal to or higher than the user’s `_swapParams.amountOutMin`
* LM’s quoted tokenIn amount + fee must not be greater than the maximum input amount specified by the user (`_swapParams.amountIn`)
* If tokenOut amount quoted is 0, the swap reverts.

6. Transfer tokenIn

Transfer the input token from msg.sender into sovereignVault. Moreover, in the case where sovereignVault == address(this), the input token is a rebase token, and pool manager fees bips for input token are non-zero: we transfer a portion of the input token amount to the poolManager as a fee. This is done to simplify accounting of rebase tokens at the pool level.

**WARNING:** In case `sovereignVault != address(this)` and `_swapParams.isSwapCallback = true` , `sovereignVault` should implement appropriate reentrancy protections, since `ISovereignPool.sovereignPoolSwapCallback` can re-enter.

7. Update state variables

Update pool’s state variables, including: reserves of token0 and token1 (in case of non-rebase tokens), and feePoolManager0 or feePoolManager1 (in case of non-rebase tokens).

8. Call Oracle Module

Update Oracle Module’s state with the latest swap data: amountInUsed, amountOut and effectiveFee.

9. Transfer tokenOut

Transfer funds to _swapParams.recipient . If liquidity is stored in the pool the funds are transferred directly using ERC20 transfer(), otherwise sovereignVault is expected to approve the pool before hand, which then transfers funds to _swapParams.recipient to via ERC-20 transferFrom(...)

10. Callbacks

Perform the following callbacks on swap end:

* Call swap fee module, if its returned data payload is non empty.
* Call LM, in case it needs to.

11. Unlock Pool

All state modifying functions in the pool are unlocked.

Last updated