Contracts
Source: clc-protocol. Spec: docs/SPEC.md.
License: AGPL-3.0 (Solady snippets stay MIT).
Units
Fees and rates use PPM: 1_000_000 = 100%. 10_000 = 1%. 100_000 = 10%.
Deployment pattern
Stateful contracts: implementation (_disableInitializers in constructor) + ERC-1967 proxy from Solady ERC1967Factory + one-time initialize.
Plain (no proxy): ERC1967Factory, DecimalQuoter, SwapRouter, RescueVault, Calibur.
ge-publish refuses --admin == --owner. Seal on SwapPool / EthFaucet is only a commitment if a different key can upgradeTo.
| Contract | Count | Job |
|---|---|---|
| GiftableToken | many | Voucher ERC-20 |
| SwapPool | many | Vault + swap |
| TokenUniqueSymbolIndex | per pool + network Token/Pool indexes | have(token) whitelist |
| Limiter | per pool | Deposit caps |
| FeePolicy | per pool | Swap fee PPM |
| DecimalQuoter / RelativeQuoter / OracleQuoter | shared or per pool | valueFor / reverseValueFor |
| ProtocolFeeController | one per network | Network fee |
| SwapRouter | one | Multi-hop quotes (eth_call only) |
| ContractRegistry | one | Identifier → address |
| AccountsIndex | one | Registered users |
| Calibur | one impl | EIP-7702 account |
All proxied contracts reject owner == address(0) in initialize.
Writer role
Owner grants limited write access without handing over ownership: GiftableToken (minters), Limiter, CAT, AccountsIndex, TokenUniqueSymbolIndex.
isWriter includes the owner except on TokenUniqueSymbolIndex, where it is the raw flag.
Quoter interface
valueFor(out, in, amount) // forward
reverseValueFor(out, in, desiredOut) // inverse, rounded upGuarantee: valueFor(out, in, reverseValueFor(out, in, x)) >= x. SwapPool uses the forward path for swaps / getAmountOut and the reverse path for getAmountIn.