SwapPool
Vault + swap engine. ERC-20 metadata (name/symbol/decimals) but no LP tokens.
Proxy: yes. Implementation 0x9e694D34…4160D.
Injected deps
Set in initialize or later via setters, until sealed.
| Slot | Interface | If unset |
|---|---|---|
tokenRegistry | have(address) | any token allowed |
tokenLimiter | limitOf(token, pool) | uncapped |
quoter | IQuoter | 1:1 |
feePolicy | getFee | pool fee 0 |
feeAddress | n/a | fees not accrued |
protocolFeeController | getProtocolFee + recipient | no protocol fee |
feesDecoupled | n/a | fees stay in inventory |
Swap
Prefer the bounded form:
withdraw(tokenOut, tokenIn, value, recipient, minAmountOut, deadline)Shorter overloads send to msg.sender and skip slippage/deadline.
Flow (nonReentrant):
tokenIn == tokenOut→InvalidToken.- Deposit
tokenIn. Registry + limiter apply.receivedis the balance delta (fee-on-transfer safe). Zero delta →TransferFailed. EmitsDeposit. quotedValue = quoter.valueFor(tokenOut, tokenIn, received)(orreceivedif no quoter).- Pool fee:
quotedValue * feePpm / PPM. - Protocol fee on top (see Fees).
- Recipient gets
quotedValue - poolFee - protocolFee. Protocol cut is transferred in the same call. - Pool fee recorded in
fees[tokenOut]iffeeAddress != 0. Swap+SwapSettlementevents.
Swap.initiator is always msg.sender. Expect a Deposit immediately before each Swap.
getAmountOut / getAmountIn revert instead of returning 0 (FeeTooHigh, InsufficientOutput). Do not treat a revert as a zero quote.
Seal
Bits can only be set, never cleared.
| Constant | Value | Locks |
|---|---|---|
FEE_STATE | 1 | feePolicy |
FEEADDRESS_STATE | 2 | feeAddress |
QUOTER_STATE | 4 | quoter |
REGISTRY_STATE | 8 | tokenRegistry |
LIMITER_STATE | 16 | tokenLimiter |
maxSealState | 31 | all five |
Sealing an unset required slot reverts InvalidState. Seal locks the slot, not the callee. A sealed quoter can still change its own rates.
isSealed(0) compares against the mask stored at init (fullSealMask), so adding a bit in a later implementation does not silently unseal old pools.
Fees in inventory
feesDecoupled = false(default): accrued fees count as liquidity.true: available =balance - fees[token].withdrawLiquiditycannot take the reserved fees.
Owner collects with withdraw(tokenOut) / withdraw(tokenOut, value) to feeAddress.
Owner emergency: withdrawLiquidity(token, to, amount).
Constants
DEFAULT_FEE_PPM = 10_000 (1%). Floor used when computing the protocol cut, so a pool cannot shrink the protocol's share by setting a tiny pool fee.