Contracts
Reference for the Zest Protocol concentrated liquidity contracts on Stacks mainnet: their addresses, the live pools, and the pool, router, LP token and governance functions.
Deployed Contracts
Zest Protocol CLMM is live on Stacks mainnet. All contracts are deployed by SP2NK9P261ZN3ZG2M1DS68PCJCRDFZVFMPYA6ZEST.
| Contract | Role |
|---|---|
clmm-pool-v1 | Holds every pool and bin, executes swaps, deposits and withdrawals, and keeps protocol fees |
clmm-router-v1 | Stateless batching and routing on top of the pool: multi-bin and multi-pool swaps, fill-or-kill, batched deposits |
clmm-lp-token-v1 | SIP-013 bin shares, one token id per bin |
executor-dao | Executes governance proposals |
operators | 2-of-3 multisig that approves proposals |
All pools live in one pool contract and are identified by a numeric pool-id. The router holds no state and no funds: every call executes as the transaction sender.
Pools on Mainnet
| Pool ID | Pair (X / Y) | Bin width | Swap fee | LP share of the fee |
|---|---|---|---|---|
| 1 | STX / USDCx | 1% | 0.30% each way | 80% |
| 2 | ZEST / STX | 1% | 1% each way | 100% |
The pools use these token contracts:
| Token | Contract |
|---|---|
| STX | SP1A27KFY4XERQCCRCARCYD1CC5N7M6688BSYADJ7.wstx, registered as a native STX token, so the pool moves STX itself |
| USDCx | SP120SBRBQJ00MCWS7TM5R8WJNTTKD5K0HFRC2CNE.usdcx |
| ZEST | SP1A27KFY4XERQCCRCARCYD1CC5N7M6688BSYADJ7.zest-token |
Governance can change a pool’s fees and state by proposal, so get-pool is the source for a pool’s current settings.
Units
- Prices in function arguments are WAD: 10¹⁸ is a price of 1 token X per token Y, in raw base units.
- Fee rates, LP fee shares, discounts and percentages are in units of 10⁸:
u100000000is 100%. - Bin steps are basis points:
u100,u500,u1000oru2000. - Deadlines are Unix seconds, compared with the timestamp of the block the transaction is mined in.
Integration Rules
- Pass the pool’s own tokens. Every call takes the two token contracts as traits, and they must be the pool’s token X and token Y.
- Order ticks by price. Ascending for X to Y, descending for Y to X.
- Set real limits. Pass a price limit, a minimum output from the quote and a short deadline on every swap.
- Use post-conditions in deny mode. Account for every token that leaves the signer.
- Redeem shares directly. The pool redeems shares only for an owner that calls it directly. Withdrawals cannot be batched through another contract.
- Find positions from events. The LP token keeps no per-owner list of token ids; index its
sft_mint,sft_burnandsft_transferevents.
clmm-pool-v1
Purpose: Pools, bins, swaps, positions and protocol fees for every Zest Protocol CLMM pool.
List of Core Functions
Positions
- add-to-position: Deposit into one bin and mint its shares
- reduce-position: Withdraw a percentage of the caller’s shares in one bin
- reduce-positions: Withdraw from up to 64 bins in one call
Swaps
- swap-x-for-y-ioc, swap-y-for-x-ioc: Swap inside one bin, immediate-or-cancel
- swap-x-for-y-route, swap-y-for-x-route: Swap across up to 32 bins of one pool (also reached through the router)
Queries
- get-pool: A pool’s tokens, bin step, fees, state and depositor
- get-pool-id: The public pool for a token pair and bin step
- get-pool-count: Number of pools created
- get-bin-state: A bin’s reserves, share supply and liquidity
- get-pool-balances: A bin’s stored reserves and supply
- get-bin-price: A bin’s current price (WAD)
- get-pool-fees: A pool’s accrued protocol fees
- get-fee-rates, get-fee-discount: The rates and discount an address has in a pool
- get-liquidity-token-id, parse-liquidity-token-id: Convert between a bin and its share token id
- is-native-stx-token, is-listed-token: Token registration state
- quote-swap-x-for-y, quote-swap-y-for-x (and
-asvariants): Single-bin swap quotes - quote-add-to-position (and
-asvariant): Deposit quote - simulate-swap-x-for-y, simulate-swap-y-for-x, simulate-deposit: Quotes against any reserves
Governance
- create-pool, create-private-pool: List a pool
- set-pool-depositor: Reassign a private pool to a new depositor
- update-pool-fee: Change fee rates and the LP fee share
- set-fee-discount: Give an address a discount on a public pool
- set-pool-status: Pause or sunset a pool
- set-native-stx-token: Register a token that moves native STX
- claim-fees: Pay out accrued protocol fees
Function Parameters
add-to-position
Deposit exact amounts of X and Y into one bin and mint its shares. Fails while the pool is paused or sunset. In a private pool only the depositor can call it.
| Parameter | Type | Description |
|---|---|---|
| token-x-trait | <ft-trait> | The pool’s token X |
| token-y-trait | <ft-trait> | The pool’s token Y |
| pool-id | uint | Pool to deposit into |
| tick | int | Bin to deposit into |
| dx | uint | Amount of X to deposit |
| dy | uint | Amount of Y to deposit |
| min-price | uint | Lowest bin price after the deposit to accept (WAD) |
| max-price | uint | Highest bin price after the deposit to accept (WAD) |
| min-shares | uint | Fewest shares to accept |
Returns: (response { dx: uint, dy: uint, shares: uint, fee-x: uint, fee-y: uint } uint). Amounts deposited, shares minted and the implicit swap fee charged
reduce-position
Burn a percentage of the caller’s shares in one bin and pay out the matching reserves. Works in every pool state. The caller must call the pool directly.
| Parameter | Type | Description |
|---|---|---|
| token-x-trait | <ft-trait> | The pool’s token X |
| token-y-trait | <ft-trait> | The pool’s token Y |
| pool-id | uint | Pool to withdraw from |
| tick | int | Bin to withdraw from |
| percent | uint | Share of the caller’s shares to burn (10⁸ = 100%) |
| min-dx | uint | Fewest X tokens to accept |
| min-dy | uint | Fewest Y tokens to accept |
Returns: (response { shares: uint, dx: uint, dy: uint } uint). Shares burned and tokens paid out
reduce-positions
Withdraw from up to 64 bins of one pool and pay each token once. Bins whose burn rounds to zero are skipped. Works in every pool state. The caller must call the pool directly.
| Parameter | Type | Description |
|---|---|---|
| token-x-trait | <ft-trait> | The pool’s token X |
| token-y-trait | <ft-trait> | The pool’s token Y |
| pool-id | uint | Pool to withdraw from |
| items | (list 64 { tick: int, percent: uint }) | Bins and percentages to burn |
| min-dx | uint | Fewest X tokens in total |
| min-dy | uint | Fewest Y tokens in total |
Returns: (response { shares: uint, dx: uint, dy: uint } uint). Total shares burned and tokens paid out
swap-x-for-y-ioc
Sell X for Y inside one bin. Spends as much of dx as fits before the price reaches max-price or the bin runs out of Y. Fails while paused.
| Parameter | Type | Description |
|---|---|---|
| token-x-trait | <ft-trait> | The pool’s token X |
| token-y-trait | <ft-trait> | The pool’s token Y |
| pool-id | uint | Pool to trade in |
| tick | int | Bin to trade in |
| dx | uint | Most X to spend, fee included |
| max-price | uint | Highest marginal price to trade at (WAD) |
| min-dy | uint | Fewest Y tokens to accept |
| deadline | uint | Unix seconds; reverts in a block mined after this |
Returns: (response { dx: uint, dy: uint, fee: uint } uint). X spent, Y received and the fee charged
swap-y-for-x-ioc is the mirror image: it takes dy, min-price and min-dx.
get-pool
| Parameter | Type | Description |
|---|---|---|
| pool-id | uint | Pool to read |
Returns: (optional { token-x, token-y, bin-step, fee-rate-x, fee-rate-y, fee-rebate, sunset, paused, native-x, native-y, depositor, discounts }). depositor is none for a public pool; discounts counts the pool’s partner discounts
get-bin-state
| Parameter | Type | Description |
|---|---|---|
| pool-id | uint | Pool to read |
| tick | int | Bin to read |
Returns: (response { balance-x: uint, balance-y: uint, total-supply: uint, liquidity: uint } uint). The bin’s reserves, share supply and liquidity in one read
clmm-router-v1
Purpose: Batching and routing on top of clmm-pool-v1. Stateless; every call executes as the transaction sender.
List of Core Functions
- add-to-positions-many: Deposit into up to 100 bins of one pool
- swap-x-for-y, swap-y-for-x: Swap across up to 32 bins of one pool
- swap-x-for-y-fok, swap-y-for-x-fok: Single-bin swap that must spend the whole input
- swap-routes: Swap through up to 9 pools in sequence
Function Parameters
swap-x-for-y
Sell X for Y across the listed bins of one pool, in strictly ascending tick order.
| Parameter | Type | Description |
|---|---|---|
| token-x-trait | <ft-trait> | The pool’s token X |
| token-y-trait | <ft-trait> | The pool’s token Y |
| pool-id | uint | Pool to trade in |
| dx | uint | X to spend, fee included |
| max-price | uint | Highest marginal price to trade at (WAD) |
| ticks | (list 32 int) | Bins to walk, strictly ascending |
| min-dy | uint | Fewest Y tokens to accept in total |
| allow-partial-fill | bool | False to revert unless all of dx is spent |
| deadline | uint | Unix seconds; reverts in a block mined after this |
Returns: (response { dx: uint, dy: uint, fee: uint } uint). X spent, Y received and the fee charged
swap-y-for-x is the mirror image: it takes dy, min-price, strictly descending ticks and min-dx.
swap-routes
Swap through a sequence of pools. Every hop must fill completely.
| Parameter | Type | Description |
|---|---|---|
| tokens | (list 10 <ft-trait>) | The path: the first token is sold, the last bought |
| routes | (list 9 { pool-id: uint, ticks: (list 32 int), x-for-y: bool }) | One entry per hop, with its bins and direction |
| token-in | uint | Amount of the first token to sell |
| min-token-out | uint | Fewest of the last token to accept |
| deadline | uint | Unix seconds; applies to every hop |
Returns: (response { token-in: uint, token-out: uint } uint). Amount sold and amount received
add-to-positions-many
Deposit into up to 100 bins of one pool in one transaction. Each entry is passed to add-to-position with its own amounts and bounds.
| Parameter | Type | Description |
|---|---|---|
| token-x-trait | <ft-trait> | The pool’s token X |
| token-y-trait | <ft-trait> | The pool’s token Y |
| pool-id | uint | Pool to deposit into |
| positions | (list 100 { tick: int, max-x: uint, max-y: uint, min-price: uint, max-price: uint, min-shares: uint }) | One entry per bin |
Returns: (response (list 100 { dx, dy, shares, fee-x, fee-y }) uint). One result per bin
clmm-lp-token-v1
Purpose: SIP-013 semi-fungible bin shares. Token id = pool-id × 2⁶⁴ + (tick + 2³²); one id per bin. Name Zest CLMM LP, symbol ZCLMM-LP, no decimals.
- transfer, transfer-memo: Move shares; the sender must be the immediate caller
- transfer-many, transfer-many-memo: Move up to 200 share balances at once
- get-balance, get-overall-balance: Shares an owner holds in one bin, or across all bins
- get-total-supply, get-overall-supply: Shares of one bin, or of all bins
- mint, burn: Callable only by
clmm-pool-v1
Governance Contracts
executor-dao: Executes proposals and records its extensions. Constructed once, by a direct call from the deployer, with the bootstrap proposal.operators: m-of-n multisig, 2-of-3 on mainnet.approverecords an operator’s approval of a proposal and executes it at the threshold.is-operator,get-threshold,get-operator-count,get-epochandget-proposalread its state.
See Governance for what proposals can and cannot do.