priceLimit. The cook reverts when the budget is not in the Pot, fewer than minTokens SPCX_US are bought, or the average price is above maxAvgPrice; the SPCX_US bought and the unspent USDC go to recipient.
Target chains: Solana. Use --chain solana. The example uses the SPCX_US Token-2022 mint.
Prerequisites
You need thesauce command (npm install -g @eco-incorp/sauce), a Solana key to send from (a keypair file, or sauce wallet new <name> --solana), and the budget in the Pot’s USDC token account. --fund is EVM only: transfer the USDC to that token account before running the cook, not to the Pot’s address. sauce pot --chain solana --owner <your-pubkey> prints the Pot’s address; use it as the token account’s owner. See Installation.
Program
pot is the Pot the program runs on, available without declaring it; pot.USDC reads its USDC token account (Names).
solana-distributed-swap.sauce.ts
How it works
- Each
<Venue>.swap(pool, tokenIn, tokenOut, amountIn, priceLimit, minOut)is@sauce/router’s swap at that venue. It returns 0 having moved nothing for a key with no pool, a spent budget, an empty or past-limit pool, and a pool whose fee is not one rate; otherwise it trades up to the pool’s own limit,priceLimitmoved by the pool’s fee, and returns what arrived in the Pot. keptis the Pot’s USDC beyondbudget, so each pool is offered onlypot.USDC - kept. The totals are checked once, after every pool:bought >= minTokens, andspent * 10 ** 18 <= maxAvgPrice * boughtunlessmaxAvgPriceis 0.- The pools fill in the program’s order, not in order of price: each swap trades up to its pool’s own limit before the next pool is offered what is left.
sauce poolslisted Raydium’s 0.25% pool at 147.93 USDC a share with its fee, Byreal’s at 147.79 and PancakeSwap’s at 147.77. WithpriceLimitat 150, Raydium’s pool, first in the program, took the whole 1,000 USDC for 6.75963 SPCX_US, an average of 147.94, and the two cheaper pools were offered nothing (the command’s local LiteSVM copy of Solana at slot 460565379). At 147.90 (147900000000000000000), below Raydium’s price with its fee, Byreal’s and PancakeSwap’s pools filled 446.356017 USDC for 3.019138 SPCX_US, an average of 147.84, and 553.643983 USDC came back unspent (the same local copy at slot 460565433). ApriceLimitclose to the pricessauce poolslists keeps every pool near them. - The keys are written in, and the command reads each key’s nine accounts from its pool when it builds the cook. On the slots simulated, the Raydium pool at fee 0.18% could not be read, and the command refused the cook before simulating (exit 2). The commands below pass that key’s nine accounts as the System Program, the form a key with no pool takes, so its swap returns 0 and the program runs unchanged.
- Each swap walks only the tick arrays its slot gives, and past them a venue’s program fails the whole cook, so each swap at a price stops a tick inside them. On Raydium CLMM, Byreal and PancakeSwap CLMM, that window ends where the furthest of those arrays begins; where a pool’s limit takes it past there, the command reads that array’s last initialized tick and the swap walks on to a tick inside it. It also holds a pool short of its limit, or skips it, where the cook’s compute units would not cover its walk. With a budget of 100,000 USDC at slot 460512539, the PancakeSwap pool walked on (
deepTick50132 incomputeStops). Swaps at a price and compute units explains the stops. sauce compile --jsonmeasures the program at 5,329 bytes and the cook at 7,382 bytes against the 1,232-byte limit.sauce runstages the program in a code buffer and passes the cook’s accounts through an address lookup table it creates.
Run the example
1
Read the pools
found by key: Raydium.CLMM.pool(USDC, SPCX_US, 2500)), fee, liquidity and price paying USDC, with the fee and as a priceLimit, and lists the pools a distributed swap skips, with why. Here it listed pool HnBT4gtWyTNKz1VuCrg5DfC57FZSnoSLGrQ2Vjpyfkts, the one the program’s key 1800 finds, among them: its fee is more than one rate (a pool rate, decay, imbalance or dynamic fee).2
Compile
3
Simulate
--assume-balance USDC:1000 gives the Pot’s USDC account the budget in a local LiteSVM copy of the cook’s accounts, read from the cluster. Without the nine --account flags the command stopped with:4
Send
maxAvgPrice here is halfway from the simulated average to priceLimit, rounded up; a simulation with it at slot 460261350 succeeded. The nine --account flags are needed only while the command cannot read the 0.18% pool’s accounts: run the Simulate step without them first, and add them if it stops with the message above. sauce run creates the Pot and the missing token accounts the cook names (asking first, or with --yes), stages the program, creates the lookup table, sends the cook and closes the buffer. sauce tx with --owner <your-pubkey> and the Simulate step’s --args and nine --account flags printed a setup step of 14 unsigned transactions for another signer.Simulation result
Simulated on Solana at slot 460261190 with the Simulate command above, in a local LiteSVM copy. Nothing was signed or sent; values change with the slot. Lines that name the owner are left out.spent × 10^18 ÷ bought is 148144482943903461943), inside the 150 limit. Byreal’s and PancakeSwap’s pools show no balance change: the budget was spent before their turn.
With minTokens at 6.8 SPCX_US (6800000) and --expect-revert "bought below minTokens":
Next steps
- Distributed swap: the same limit order over Uniswap pools on Base
- Solana swap: one swap at one Solana pool
sauce pools,sauce simulate,sauce run
