This document describes the stablecoin market making, swapping, and liquidity provision functionality in the Spark ALM Controller.
The Spark Liquidity Layer (SLL) performs liquidity operations across multiple venues:
| Venue | Operations | Use Case |
|---|---|---|
| Curve | Add/remove liquidity, swaps | Deep stablecoin liquidity pools |
| Uniswap V4 | Swaps, positions | On-chain stablecoin swaps |
| OTC Desks | Offchain swaps | High-volume institutional liquidity |
Asset Assumption: All assets in these operations are treated as 1:1 (USD stablecoins). See Threat Model for details.
- Add Liquidity: Deposit stablecoins into Curve pools to receive LP tokens
- Remove Liquidity: Burn LP tokens to receive underlying stablecoins
- Swaps: Exchange between stablecoins in Curve pools
Curve operations use three rate limit keys per pool:
- Add liquidity rate limit: Controls the value deposited into pools
- Swap rate limit: Controls the implicit swap value when deposits are imbalanced
- Remove liquidity rate limit: Controls the value withdrawn from pools
All Curve operations require maxSlippage to be configured (cannot be zero). The slippage check uses the pool's virtual price to ensure minimum acceptable returns.
- Only 1:1 stablecoin pools can be onboarded
Curve pools must be seeded with initial liquidity before use. Seeding must be done to an unrecoverable address (e.g, address(1)). This will prevent any unintended behaviours.
- Swaps: Exchange between stablecoins via Uniswap V4 pools
- Mint Positions: Create liquidity positions (if applicable)
- Increase Positions: Deposit adfditional liquidity into an existing position
- Decrease Positions: Withdraw some or al the liquidity of an existing position
Uniswap V4 operations use three rate limit keys per pool:
- Add liquidity rate limit: Controls the value deposited into pools
- Swap rate limit: Controls the implicit swap value when deposits are imbalanced
- Remove liquidity rate limit: Controls the value withdrawn from pools
All Uniswap V4 operations require maxSlippage to be configured (cannot be zero). The slippage check uses the pool's virtual price to ensure minimum acceptable returns.
- Only 1:1 stablecoin pools can be onboarded
- Tick limits must be configured.
- Only hookless pools can be onboarded. Rate limit decreases are calculated from token balance differences before and after pool interactions, and empty
hookDatais passed. Pool hooks (if present) could manipulate token balances during the call to bypass the rate limit decrease.
Uniswap V4 pools must be seeded with initial liquidity before use. Seeding must be done to an unrecoverable address (e.g, address(1)). This will prevent any unintended behaviours.
The OTC swap module allows offchain swaps with OTC desks and exchanges while constraining capital outside the system.
- Funds are sent from the ALM Proxy to the offchain destination
- The contract prevents sending more funds until the required balance is returned
- Acts as a gating mechanism: maximum
Xfunds outside the system per approved exchange
This provides guarantees that at most X can be at risk per whitelisted OTC route, while allowing rapid throughput into high-liquidity offchain markets.
For an OTC swap to be performed, isOtcSwapReady(exchange) must return true. This function has two main components:
maxSlippages mapped on exchange, used consistently with other parts of the controller. This value calculates a minimum viable amount to be returned from a swap for it to be considered complete.
The OTC struct contains a rechargeRate value expressed in 18 decimals of token per second. This value increases over time after the initial swap is sent.
Purpose: Prevents the configuration from bricking swapping functionality if an exchange returns an amount of funds that is materially below the configured maxSlippage. The mechanism allows the amount that can be sent as part of an OTC swap to virtually "recharge" over time, to respond to deviations in recent expected claims.
An OTC swap is ready when:
OTC buffers require infinite allowance (type(uint256).max) to the ALMProxy. This allows atomic fund pulling during swap completion. otcClaim always attempts to transfer the entire buffer balance for a whitelisted asset; with finite allowances, an attacker can donate a small amount to push balance above allowance, causing claim reverts and blocking OTC readiness when recharge is zero/low. See Operational Requirements for deployment checklist.
There are two PSM integrations with different rate limit behaviors:
Operations: USDS ↔ USDC swaps (via DAI conversion)
| Operation | Rate Limit |
|---|---|
swapUSDSToUSDC |
Decreases limit |
swapUSDCToUSDS |
Cancels (restores) limit |
Rationale: Swapping USDC back to USDS returns value to the system, so rate limit is restored.
Operations: Deposit/withdraw assets to/from L2 PSM
| Operation | Rate Limit |
|---|---|
depositPSM |
Decreases limit |
withdrawPSM |
Decreases limit (no cancellation) |
Design Decision: No cancellation, no minShares.
Rationale:
- PSM3 will be deprecated soon
- The contract is immutable, limiting attack surface
- Prices cannot be manipulated due to 1:1 swap design
For deployment checklists and configuration requirements, see Operational Requirements.
