sauce commands are the ones you use on Base: compile, simulate, tx, run, pot. This page covers what differs: the accounts a transaction lists, the two ways a cook reaches the engine, the execution fee, programs too large for one transaction, Token-2022 tokens, and the accounts a run leaves open.
Prerequisites
- The
saucecommand:npm install -g @eco-incorp/sauce(Installation). - A Solana signer for
run: a Solana wallet (sauce wallet new --solana) or a keypair file for--keypair.compileandtxneed only the owner’s public key. - For
simulateandrun, the release’s engine must be deployed on the cluster:sauce pot --chain solana --owner <pubkey>reports whether it is.sauce txon Solana does not check for the engine, as it does on an EVM chain: without it, its simulation of the cook fails withAccountNotFoundand it builds no cook.
Accounts
A Solana transaction lists every account it touches. For most programs you pass none: compiling adds each account the program needs tomain, with how to derive it, and simulate, tx and run derive each one from the owner, the Pot and main’s arguments. This program pays PYUSD with the token method:
pay-pyusd.sauce.ts
sauce compile --json lists the accounts in its manifest, in order, each with its role and derivation:
pot, so its accounts derive from authority, the account that signs the engine call: the Pot through the Kitchen, and the owner with --via engine. A program that names pot anywhere derives them from the Pot (pot, pot:USDC), as payout.sauce.ts does, and runs through the Kitchen only.
The tx outputs on this page were built against Solana mainnet, where the engine and Kitchen are deployed. Nothing was signed or sent.
Name an account with —account
A program can take an account as a parameter of typeAccount, Account<Writable> or Account<Signer>. You name each one with --account NAME=<value>, or give them all at once with --accounts <json | file>, a JSON object of names to values.
A token account is the holder’s associated token account for the mint, under the token program that owns the mint. A tokenized stock is named by its symbol in any case (
pot:TSLAx). Every account a derivation needs must be known when the transaction is built.
Through the Kitchen, an account given for a slot the program derives from the Pot, the owner or authority must be the account that derivation gives, or the command exits 2. Giving the owner for pay-pyusd.sauce.ts’s pot slot:
owner, owner:USDC, a pda: the owner seeds) to the owner’s account, on simulate, run and tx, --account and --accounts alike.
A program that takes accounts and leaves them out is refused before anything is read, with the values that suit each slot and the JSON to save as an --accounts file:
sauce compile --json lists the same as accountsToGive. A wallet is not a token account: where a program writes a token account, give the wallet’s (dest=<wallet>:USDC), not the wallet itself.
Kitchen or engine: —via
simulate, tx and run take --via <kitchen|engine>:
With
--via engine nothing is created and there is no Pot, so a pot or pot:<token> account cannot be attached, and a program that uses pot, pot.balance or pot.<TOKEN> needs the Kitchen. A program that reads only pot.owner does not bind a Pot: it names the signing owner and runs with either route.
The execution fee
Every cook pays the Kitchen’s execution fee in lamports, read from the cluster, through the Kitchen or directly on the engine alike. Each output prints it asfee. The cook signs that fee as its max_execution_fee, so it pays that amount or fails if the fee rises before it lands. --max-execution-fee <lamports> sets your own ceiling, checked before anything is signed:
1. A first run also pays rent for the Pot and for each new token account, and transaction fees. sauce pot --chain solana prints the current fee.
Large programs and lookup tables
A Solana transaction holds at most 1,232 bytes.sauce compile --json with --args reports the cook’s size as cook, as sauce run would build it, through the Kitchen or with --via engine:
--via engine, the same cook is 1,048 bytes.
Staging. A cook past the limit stages its program in a Kitchen code buffer first, written over a few transactions, and runs from there. This program compiles to 1,421 bytes:
payout.sauce.ts
sauce tx prints the plan’s first step, unsigned, with a cursor for the next:
sauce send with --cursor sends a step and builds the next one from what the cluster shows. sauce run does every step itself, and closes the code buffer after the cook so its rent comes back.
Lookup tables. Each account a transaction lists costs 32 bytes; one taken through an address lookup table costs one byte. When a staged cook’s accounts do not fit, sauce run creates a lookup table, paid by the signer, prints its address, and keeps it for the next cook that names the same accounts. --lookup-table <address> on run, simulate and tx takes a cook’s accounts through a table that holds them.
Swaps at a price and compute units
A Solana transaction has 1,400,000 compute units, and a concentrated-liquidity swap spends units for every initialized tick it crosses, so a wide price limit can run a cook out of units, and a cook that runs out fails whole. For a program that swaps at a price through the venue namespaces (Orca.Whirlpool.swap(…), Raydium.CLMM.swap(…) and the rest), simulate, run and tx read each pool’s tick arrays and work out how far each swap may walk, the pool buying the most per unit first:
- Held or skipped. A pool the cook’s units do not cover is held short of its limit, or skipped when it cannot be paid for at all. Its swap is compiled to the venue’s Stopped form, with the stop added to
main’s values. - Walked on. A venue’s swap walks only the tick arrays the cook gives it. On Raydium’s code (Raydium CLMM, PancakeSwap CLMM, Byreal, Stabble CLMM) and Crema, that window ends where the furthest of those arrays begins. Where a pool’s limit takes its walk past there, the command reads that array’s last initialized tick the walk’s way, its deep tick, and compiles the swap to its Stopped form with it; the swap then walks on to a tick inside that array. The Stopped form reads the tick in its array as the cook runs: a tick no longer initialized leaves the swap where it would have stopped, and an array not laid out as read reverts (
deep: the tick array is not laid out as Raydium's, orCrema's). - Every other swap stays the plain one, and a program no stop binds is the same program, byte for byte.
--json gives every pool’s stop in computeStops, with deepTick for a walk on. tx works the stops out from a table of each venue’s costs alone, so the cook it builds can differ from the one simulate reports; simulate and run check them in a simulation first, and tighten them if the cook would still run out. A price that moves between building the cook and landing it can still run the cook out of units.
The Solana distributed swap with a budget of 100,000 USDC, simulated at slot 460512539, walked its PancakeSwap CLMM pool on into its furthest tick array:
0 for none), bits 192 to 223 a start bound past which the swap skips the pool, and bits 224 to 255 the deep tick, each tick stored with its sign bit flipped. This stop carries only the deep tick: 50132 in bits 224 to 255, and no limit or start bound. @sauce/router lists the Stopped forms.
Token-2022 checked writes
A Solana mint belongs to the SPL Token program or to Token-2022. USDC and USDT are SPL Token mints; PYUSD and the tokenized stocks are Token-2022 mints.- Token methods pick the write for the mint.
PYUSD.transfer(to, amount)compiles to a checked transfer, with the registry’s decimals and the mint as one more account. The manifest above shows it:token2022ProgramandmintPYUSD. - Explicit checked writes work with either token program:
transferChecked(mint, tokenProgram, source, mintAccount, dest, authority, amount, decimals)andapproveChecked(mint, tokenProgram, source, mintAccount, delegate, authority, amount, decimals). The program requirestokenProgramto be one of the two token programs and to own the source, the destination and the mint;mintAccountto bemint; anddecimalsto be the mint’s. - Legacy writes,
transfer,transferFromandapprovewith explicit accounts, are SPL Token only. Token-2022 refuses its plain transfer for a mint with a transfer fee, a transfer hook or a pause.
transfer hook. A transfer fee is withheld from what the destination receives, so measure the balance that arrived rather than the amount sent.
This program moves a Token-2022 amount between accounts named on the command line:
sweep.sauce.ts
Building a cook
Build cooks with the installedsauce command or SDK, which use the engine and Kitchen on Deployments. The Kitchen validates the named pot account with the salt and the Pot’s canonical bump.
The command and the SDK’s high-level client add the 262,144-byte heap frame request every cook needs. A cook you assemble yourself in TypeScript prepends buildHeapFramePrepend() from @eco-incorp/sauce/svm exactly once (Solana from TypeScript).
Leftovers and sauce reclaim
A run closes the code buffer it staged. A run that was stopped, or a plan never finished, can leave a buffer open, and lookup tables stay open for later cooks.sauce reclaim lists both, with the rent they hold, and closes them:
--owner alone it prints the closing transactions unsigned; with --keypair or --wallet it sends them. A lookup table closes in two steps, about three and a half minutes apart.
Next steps
sauce run: sign and send a Solana cook.- Solana distributed swap: a program that takes pools’ accounts.
- Solana from TypeScript: build the same cooks in code.
- Kitchen: the program that runs cooks on Pots.
