cook(engine, program): engine is the V12 engine that runs the program, and program is the compiled bytecode with the encoded entry arguments appended. Its value is the Kitchen’s execution fee plus any native coin the program spends.
A Pot’s address follows from its owner and a salt, so you can compute it before the Pot exists. The Pot exists once someone has sent the Kitchen’s deployPot(owner, salt), which anyone can send once for each owner and salt. The Pot and cook pages explain both contracts.
The functions on this page build transactions and sign nothing. Only the signed-cook checks read a chain, through the client you pass them: checkSignedCookPot, cookNonceUsed, and verifySignedCook for an owner with code. Read the chain through your own client, and sign and send with your own wallet.
Complete example on Base
This script compiles a payment program for Base, encodes its arguments, predicts the owner’s Pot, reads the Kitchen fee and builds the cook. It then simulates the Pot’s deployment and the cook together with viem’ssimulateCalls, from the owner, at one block. Nothing is signed or sent.
Prerequisites
- Node.js 24 or newer, with
@eco-incorp/sauceandvieminstalled. - A Base RPC endpoint, passed as the script’s first argument. The library has none of its own.
- The release’s engine deployed on Base.
sauce pot --chain base --owner <address>reports whether it is. The script also checks: it refuses to build a cook when the engine, the Router or the Kitchen has no code, or when the Kitchen predicts a different Pot than the SDK.
The script
cook.ts
require stopped the cook and its message came back as the revert data. Pay nothing:
deploy once, where the Pot has no code, and then cook, each as { to, data, value } with any wallet library. Read the fee shortly before building the cook: a fee raised between that read and the cook makes the cook revert.
routes.buildSauceEvmCall
Builds onecook(engine, program) call on a Pot.
Import
Usage
encode-cook.ts
Signature
Parameters
Returns
SauceEvmCall, in both shapes a call is used in:
{ to, data, value }, the transaction a wallet sends orclient.calltakes.tois the Pot’s checksummed address.{ target, data, value }, a call record.targetis the same Pot as a 32-byte, lowercase, left-padded address.
value is a bigint.
Throws
It throws for an engine that the release sets in/deployments record only for compilers other than the one the SDK pins, because that engine cannot run this SDK’s programs. More than one compiler version can share an engine and Kitchen, so an engine recorded for the SDK’s compiler passes even where another set records it too. The message names the engine the SDK’s programs need. An engine no release set names is not refused.
Several programs
routes.buildSauceEvmCalls({ pot, engine, cooks, value }) returns one call per program in cooks, in order, each carrying value. Each call is a separate cook and pays the fee; statements inside one program need one cook.
v12Pot.encodeCook
The calldata encoderbuildSauceEvmCall uses: cook(engine, program) as hex. v12Pot also carries the Pot’s ABI as v12Pot.abi; v12PotAbi is the same ABI as a separate export.
Import
Usage
encode-cook.ts above compares it with buildSauceEvmCall:
Signature
Parameters
Returns
Hex: the cook(engine, program) calldata.
Throws
The same refusal asbuildSauceEvmCall, for an engine that the release sets record only for other compilers.
Signed cooks
A Private Pot runs a cook its owner signed, sent by any account, through the Pot’scookSigned (Signed cooks). The owner signs EIP-712 typed data; the sender sends cookSigned with exactly the signed value and pays the gas; the Pot pays the Kitchen’s fee from its own balance, up to the signed ceiling. @eco-incorp/sauce/evm/engine builds each part, and your wallet signs. sauce sign builds the same from a terminal.
Import
Usage
sign-cook.ts
program the payment program of the complete example paying 1 USDC, and a freshly deployed Pot holding 5 USDC and 0.001 ETH:
- before the Pot was deployed,
checkSignedCookPotreturned{ ok: false, reason: "0xFbfB…43E1 has no code: no Pot is deployed there" }, and after it,{ ok: true, owner }; sendwas 676 bytes ofcookSignedcalldata to the Pot, withvalue0n. A second account sent it: the cook succeeded with 121110 gas, and the recipient received 1000000 USDC base units;cookNonceUsed(client, pot, cook.nonce)then returnedtrue;- a second signature’s
cancel, sent by the owner, set its nonce, and itssendthen reverted withNonceUsed().
Exports
checkSignedCookPot checks the Pot before you sign. The @eco-incorp/sauce reference has each signature. Security considerations covers replay, deadlines, the submitter and the fee ceiling.
v12PredictPot
Computes a Pot’s address from its owner and salt, with no chain read:CREATE2(kitchen, keccak256(abi.encode(owner, salt)), initCodeHash), the init-code hash taken from the pinned release.
Import
Usage
pot.ts
Signature
Parameters
Returns
Hex: the Pot’s address. It is the same on every chain where the Kitchen is deployed at the same address. The address is arithmetic, not proof that a Pot exists: check for code with client.getCode, as the complete example does.
A Pot’s address is keyed to the Kitchen, the owner and the salt, and the Pot’s bytecode is part of it. An engine runs only a Pot that its paired Kitchen created (Compiler and engine pairing); a balance never moves between Pots on its own.
DEFAULT_POT_SALT and potSalt
DEFAULT_POT_SALT is the salt of an owner’s default Pot: 32 zero bytes. potSalt(label) is the salt of a Pot the owner names label: keccak256 of the label’s UTF-8 bytes. The sauce command’s --salt treasury is potSalt("treasury"). For an exact salt, pass its 32 bytes to v12PredictPot as they are.
Import
Usage
pot.ts above prints both salts and the two Pots they give one owner.
Signature
Throws
potSalt("") throws: potSalt: a label names a Pot, so it cannot be empty — the default Pot's salt is DEFAULT_POT_SALT.
routes.sauceEvmDeployPotCall
Builds the Kitchen’sdeployPot(owner, salt) call, the transaction that creates a Pot. Send it before the first cook on a Pot that has no code yet.
Import
Usage
pot.ts above builds one and checks it against v12Kitchen.encodeDeployPot from /evm/engine.
Signature
Parameters
Returns
SauceEvmCall: { to, target, data, value } with to the Kitchen and value 0n. It reads no chain, so it does not know whether the Kitchen has code where you send it, or whether the Pot already exists.
kitchenExecutionFee
Builds the read of the Kitchen’sexecutionFee() and its decoder. It performs no request: you send it as an eth_call. The fee can change on chain, so read it shortly before building a cook.
Import
Usage
From the complete example:Signature
Parameters
Returns
ExecutionFeeCall: to and data for the eth_call, and decode, which turns its result into the fee in the chain’s native unit.
Release addresses
@eco-incorp/sauce/deployments returns the addresses of the pinned V12 release: the same on every chain, recorded rather than read from one. The values are on Deployments. The SDK reads no chain, so check that a chain has code at an address before you rely on it.
Next steps
- Entry arguments: encode the arguments in the payload.
- Compiling: compile the program.
- sauce tx and sauce simulate: the same transaction and simulation from a terminal.
- sauce pot: a Pot’s address, code and Kitchen fee from a terminal.
- Deployments: the release addresses.
- Kitchen, Pot and cook: the contracts these transactions call.
