> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eco.com/llms.txt
> Use this file to discover all available pages before exploring further.

# sauce sign

> Sign a cook on your Pot for another account to send and pay the gas for, check a signature made elsewhere, or cancel one

`sauce sign` signs a cook on your Pot without sending it: another account sends the transaction it prints, pays the gas, and the Pot runs exactly the program you signed.

## Synopsis

```bash theme={null}
sauce sign <file | -> --chain <slug|id> (--wallet <name> | --keystore <path> | --private-key <hex> | --owner <address> | --pot <address>) [--salt <label> | --salt-hex <bytes32>] [--within <seconds> | --deadline <unix seconds>] [--submitter <address>] [--max-fee <wei>] [--value <wei>] [--nonce <n>] [--signature <hex>] [--rpc-url <url> | --config <file> | --offline] [--json] [--args …]
sauce sign --cancel <nonce> [--cancel <nonce>]… --chain <slug|id> (--wallet <name> | --keystore <path> | --private-key <hex> | --owner <address> | --pot <address>) [--rpc-url <url> | --config <file> | --offline] [--json]
```

## Description

`sauce sign` compiles the file with `main`'s arguments, as [`sauce tx`](https://docs.eco.com/sauce-sdk/cli/tx) does, and prints what the Pot's owner signs so that another account can submit the cook through the Pot's `cookSigned` ([Signed cooks](https://docs.eco.com/sauce/pot.md#signed-cooks)). The owner signs EIP-712 typed data, a `Cook` under the domain `{ name: "Sauce Pot", version: "1", chainId, verifyingContract: <the Pot> }`, so a signature is good for one Pot on one chain. The `Cook` binds:

| Field | What it binds |
| - | - |
| `engine` | The engine the Pot runs the program on |
| `program` | The bytecode with `main`'s arguments appended, all of it |
| `value` | What the sender must send with the cook, exactly: `--value`, default 0 |
| `maxExecutionFee` | The most of the Kitchen's fee the Pot pays: `--max-fee`, default the fee read from the chain now |
| `nonce` | The authorization's number; each nonce runs once: `--nonce`, default a random 256-bit nonce |
| `deadline` | The last second it runs, inclusive: `--deadline`, or the chain's latest block plus `--within` (default 3600 seconds) |
| `submitter` | The only account that may send it: `--submitter`, default the zero address, which lets anyone send it |

**With a signer** (the Pot's owner, by `--wallet`, `--keystore` or `--private-key`) it signs, and `cook` is the transaction to send: `{ chainId, to: <the Pot>, data: cookSigned(…), value }`, spelled as `sauce tx` spells a transaction. **Without a signer** (`--owner` or `--pot`) it prints the typed data for any wallet's `eth_signTypedData_v4`. Given that signature with `--signature`, it checks that the owner made it and builds `cook`. An owner that is a contract, such as a Safe or an EIP-7702 account, is asked through its own ERC-1271 `isValidSignature`, which needs an endpoint. A signature that does not check is refused.

**Sending it.** Any account sends `cook` with exactly its `value`: the Pot checks the value it receives against the signed one. The sender pays the gas and nothing else. The Pot pays the Kitchen's fee from its own balance, which includes the value sent, up to the signed ceiling, so keep native coin in the deployed Pot or sign a value that covers the fee. A cook that reverts leaves its nonce unused, and the same signature can be sent again until the deadline. Whoever holds the output can send it until then.

**The Pot.** With an endpoint the command reads the Pot first:

* A Pot with no code yet that `--owner` (or the signer) and the salt name is still signed for, and the output carries `deployPot`, the Kitchen's `deployPot` call, which any account sends first.
* A Pot without `cookSigned`, a Shared Pot, a contract that is not a Pot, and a Pot named only by `--pot` that has no code are refused, with the reason.
* It reads the Kitchen's fee and the Pot's balance, and warns when the two do not cover the fee.

`--offline` reads nothing, so it then needs `--max-fee`.

**Cancelling.** `--cancel <nonce>` (repeatable) cancels instead of signing: one `invalidateNonces(word, mask)` to the Pot per word of nonces, from its owner. With a signer and an endpoint they are sent. Without a signer they are printed unsigned, for the owner to sign and [`sauce send`](https://docs.eco.com/sauce-sdk/cli/send) to send. A cancelled nonce stays cancelled.

**A wallet's policy.** From a wallet with a [spending policy](https://docs.eco.com/sauce-sdk/cli/wallets-and-policy.md), the policy's `chains` and `to` apply, with the Pot as the address. A `native` or `tokens` limit refuses the signature, naming the limit: a signed cook runs when someone else sends it, on the chain's state then, so what it moves cannot be measured when it is signed.

`sauce sign` signs and cancels only on a supported EVM chain: Ethereum, Base and Arc, and the testnets Arc Testnet, Base Sepolia and Ethereum Sepolia. On a preview chain it is refused before anything is read or signed, with a message that names the supported chains and how to request the refused one. On Solana, Solana Devnet and Solana Testnet there is no signed cook, because the Kitchen's cook already takes the owner's signature and a separate fee payer: the command refuses it.

## Prerequisites

* A Pot created by the current Kitchen, or one not deployed yet. The release's engine must be deployed on the chain: `sauce pot --chain <chain> --owner <address>` reports whether it is.
* The Pot's owner as a signer, or the owner's address and a wallet elsewhere that signs EIP-712 typed data.

## Options

| Option | Description |
| - | - |
| `--chain <slug\|id>` | The chain the program runs on (`base`, `8453`) |
| `--target <evm\|svm>` | Checked against the chain. `svm` with no `--chain` means Solana |
| `--source-dir <dir>` | The directory the program's relative imports resolve from. Default: beside the file; for stdin, the current directory |
| `--owner <address>` | The Pot's owner, which derives the Pot with the salt. Default: the signer |
| `--pot <address>` | The Pot itself, by address |
| `--salt <label>` | Name one of the owner's Pots: the salt is `keccak256(label)` |
| `--salt-hex <bytes32>` | Give the Pot's salt exactly |
| `--args-json <json\|file>` | `main`'s arguments as one JSON array, inline or in a file |
| `--value <wei>` | What the sender sends with the cook, signed exactly. Default 0 |
| `--max-fee <wei>` | The most of the Kitchen's fee the Pot pays, signed. Default: the fee read now |
| `--nonce <n>` | The nonce the cook runs once under. Default: random |
| `--within <seconds>` | How long it can be sent, from the chain's latest block. Default 3600 |
| `--deadline <unix seconds>` | The last second it can be sent, exactly, inclusive |
| `--submitter <address>` | The only account that may send it. Default: anyone |
| `--signature <hex>` | The owner's signature of the typed data, made elsewhere: checked, then the cook is built |
| `--cancel <nonce>` | Cancel this nonce instead (repeatable): `invalidateNonces` on the Pot, from its owner |
| `--wallet <name>` | Sign as the Pot's owner with an EVM wallet of the wallet directory ([`sauce wallet`](https://docs.eco.com/sauce-sdk/cli/wallet)) |
| `--wallets [<dir>]` | The wallet directory. Default: `~/.sauce/wallets` |
| `--password-env <NAME>` | The wallet's password is the environment variable `NAME`, the only one read |
| `--password-file <path>` | The password is in a file only you can read. Without a source, it is asked for |
| `--password-command <command>` | The password is what this command prints, such as a secret manager's CLI |
| `--keystore <path>` | Sign with a JSON keystore (v3), with a password source |
| `--private-key <hex>` | Sign with a raw key, which lands in shell history |
| `--rpc-url <url>` | Your own RPC endpoint for the chain. Default: a built-in public one |
| `--config <file>` | A file of your own endpoints: `{ "rpcUrls": { "<chain id>": "<url>" } }` |
| `--offline` | Read no chain: no endpoint, built-in ones included. `--max-fee` is then required |
| `--json` | Signing a cook prints the same JSON object and notes with it or without. Unsigned cancellations add `sendCalls` with it. Cancellations that were sent print JSON with it, and a line per transaction without it |
| `-h, --help` | Show the help |
| `--no-update-check` | Print no notice of a newer `sauce`, and read no registry for one |
| `--args <value>…` | `main`'s arguments in order: an integer as digits, a negative one too (`-5`), JSON for an array or a tuple. Put `--` before a word that starts like a flag |

### Low-level options

`--help` lists these apart, with the note "a program's inputs are main's parameters, given with --args".

| Option | Description |
| - | - |
| `--define NAME=VALUE` | A compile-time value for a name the program leaves undeclared: an integer, `0x` hex, `true` or `false` |
| `--defines <file.json>` | Compile-time values from a JSON object of name to value. `--define` takes precedence |

## Output

Signing a cook prints one JSON object on stdout, with `--json` or without, and its notes on stderr either way, the fee warning among them: the Pot and its owner, who may send the cook and until when, whether the Pot needs deploying first, what the sender sends, the Kitchen's fee beside the signed ceiling and what the Pot holds, and the command that cancels it.

| Field | Contents |
| - | - |
| `chainId`, `pot`, `owner`, `engine` | The chain, the Pot, its owner and the engine signed |
| `program` | The bytecode with `main`'s arguments appended, as signed |
| `value`, `maxExecutionFee`, `nonce`, `deadline`, `submitter` | What was signed. Amounts, the nonce and the deadline are decimal strings |
| `typedData` | The EIP-712 typed data, as `eth_signTypedData_v4` takes it |
| `digest` | The 32-byte hash the signature is over |
| `signature` | The owner's signature. Absent when nothing signed |
| `cook` | The transaction the sender sends: `{ chainId, to, data, value }`, `value` in hex. Absent when nothing signed |
| `deployPot` | Only while the Pot has no code: its deployment, for any account to send before `cook` |

With `--cancel`, unsigned, the object is `{ chainId, pot, owner, nonces, transactions }`, one entry of `transactions` per word of nonces: `{ what, chainId, to, data, value, word, mask }`. With `--json` it also carries `sendCalls`, `{ chain, calls: [{ to, value, data }] }`: the same calls as one batch, for a wallet that sends a batch (EIP-5792). Without `--json` there is no `sendCalls`. Sent, it is `{ chainId, pot, from, nonces, sent }` with `--json`, each entry of `sent` `{ what, word, mask, hash, explorer, trace, status, gasUsed, blockNumber }`. Without `--json`, the command prints one line per cancellation instead (its hash, status, gas used and block), followed by its explorer and trace links where the chain has them.

Exit codes: `0` when the cook is signed or printed, or the cancellations sent or printed; `1` on a refusal (a preview chain, a Pot that does not take signed cooks, a signature that does not check, a wallet's policy); `2` for a usage error, such as `--offline` without `--max-fee`, or Solana.

## Examples

The examples ran on a local fork of Base at block 52991146 with the current contracts. They sign the cook of [`pay.sauce.ts`](https://docs.eco.com/sauce-sdk/cli/compile#compile-for-base), which pays 1 USDC from the Pot, from the throwaway wallet `agent`, whose Pot had no code. Long numbers are cut short, and the engine's and Kitchen's addresses are shown as placeholders (see [deployments](https://docs.eco.com/sauce-sdk/reference/deployments.md)).

### Sign with a wallet

```bash theme={null}
sauce sign pay.sauce.ts --chain base --wallet agent --password-env SAUCE_WALLET_PASSWORD \
  --within 600 --args 0x4444444444444444444444444444444444444444 1000000
```

```json theme={null}
{
  "chainId": 8453,
  "pot": "0x85752c778B8271DEF249b7f8Ca078963bCc8a74D",
  "owner": "0xD0D7074037E4B410DFb44ee711Db2C54ABBB27fA",
  "engine": "<engine address>",
  "program": "0xa502011fd1514702000eb1…",
  "value": "0",
  "maxExecutionFee": "3744785386350",
  "nonce": "103230220937744476905763495772860658510666713811464932154642668374586231393688",
  "deadline": "1792773536",
  "submitter": "0x0000000000000000000000000000000000000000",
  "typedData": { "domain": { "name": "Sauce Pot", "version": "1", "chainId": "8453", "verifyingContract": "0x85752c778B8271DEF249b7f8Ca078963bCc8a74D" }, "types": { … }, "primaryType": "Cook", "message": { … } },
  "digest": "0x93aada68c70d826fd3ae3dc05522d103595ccf83eea5a1123cb9f7625d2782fe",
  "signature": "0xf1e8222f36b1403d175b8d…",
  "cook": { "chainId": 8453, "to": "0x85752c778B8271DEF249b7f8Ca078963bCc8a74D", "data": "0x1e6fb6b5…", "value": "0x0" },
  "deployPot": { "chainId": 8453, "to": "<kitchen address>", "data": "0xff9763ac…", "value": "0x0" }
}
```

```text theme={null}
Pot 0x85752c778B8271DEF249b7f8Ca078963bCc8a74D, owned by 0xD0D7074037E4B410DFb44ee711Db2C54ABBB27fA: Anyone may submit this cook, once (nonce 1032302209…393688), until 1792773536 (2026-10-23T16:38:56.000Z), unix seconds, inclusive.
Pot 0x85752c778B8271DEF249b7f8Ca078963bCc8a74D has no code yet: send deployPot first (Kitchen.deployPot; any account may send it, and the Pot is its owner's either way), then the cook.
Send cook from any account with exactly 0 wei of value, and nothing more (the Pot hashes the value it is sent): sign it with any wallet and broadcast it (sauce send <signed transaction>), or pass it to a wallet's send tool. The submitter pays gas, and nothing else.
The Pot pays the Kitchen's fee itself, from its balance and the cook's value: the fee is 3744785386350 wei (0.00000374478538635 ETH) now, the signed ceiling 3744785386350 wei (0.00000374478538635 ETH), and the Pot holds 0 wei (0 ETH).
warning: the Pot's balance and the cook's value (0 wei) do not cover the Kitchen's fee: fund the Pot before the cook is submitted, or it reverts with FeeNotPaid.
Whoever holds the signature may submit it until the deadline. Cancel it before then with sauce sign --cancel 1032302209…393688 --chain base, signed by the owner. A cook that reverts leaves its nonce unused, so the same signature can be submitted again until the deadline.
```

The Pot in this example has no code, so the warning's advice to fund it applies once `deployPot` has landed: send `deployPot`, fund the deployed Pot, then submit the cook ([Funding a Pot](https://docs.eco.com/sauce-sdk/cli/funding.md)).

### Send it from another account

On a live EVM chain, put nothing at the Pot's address before it is deployed. Send `deployPot` on its own (`sauce send <signed deployPot> --rpc-url <url>`), fund the deployed Pot, then send the signed cook.

On a local fork the Pot's address already held 5 USDC and 0.001 ETH when a second account signed `deployPot` and `cook` as ordinary transactions and sent both with one command:

```bash theme={null}
sauce send <signed deployPot> <signed cook> --rpc-url <url>
```

```text theme={null}
Kitchen.deployPot at <kitchen address> 0xef9d…7ea6: success, gas used 667003, block <block>
signed cook on Pot 0x85752c778B8271DEF249b7f8Ca078963bCc8a74D 0x44c9…a142: success, gas used 121110, block <block>
…
What moved, in order:
  [1] Pot 0x8575…a74D -> 0x4444…4444  1 USDC
Net balance changes:
  0x85752c778B8271DEF249b7f8Ca078963bCc8a74D (the Pot): -1 USDC
  0x4444444444444444444444444444444444444444: +1 USDC
```

Sent a second time, the same cook reverts with `NonceUsed()`.

### Sign with a wallet kept elsewhere

Without a signer, the command prints the typed data and signs nothing:

```bash theme={null}
sauce sign pay.sauce.ts --chain base --owner <owner> \
  --args 0x4444444444444444444444444444444444444444 1000000
```

```text stderr theme={null}
No signer was given: sign typedData with the Pot's owner (eth_signTypedData_v4), then build the cook with that signature (--signature <hex>), or sign here with --wallet, --keystore or --private-key.
```

Have the owner's wallet sign `typedData`, then run the same line with the `--max-fee`, `--nonce` and `--deadline` the first run printed, so it builds the same cook:

```bash theme={null}
sauce sign pay.sauce.ts --chain base --owner <owner> --max-fee <maxExecutionFee> --nonce <nonce> \
  --deadline <deadline> --signature <signature> --args 0x4444444444444444444444444444444444444444 1000000
```

The output then carries `signature` and `cook`. A signature made by another key is refused, and the command exits `1`:

```text theme={null}
sauce sign: the signature given is not 0x2143288aaBBB8c45C6ecC6F2609Fd13b5706812f's over this cook (digest 0x92a8…ae1f): the Pot would refuse it with BadSignature. Every field is signed: the program and its arguments, value, the fee ceiling, nonce, deadline and submitter must be what the owner signed
```

### Let one account send it

```bash theme={null}
sauce sign pay.sauce.ts --chain base --wallet agent --password-env SAUCE_WALLET_PASSWORD \
  --submitter <relayer> --within 600 --args 0x4444444444444444444444444444444444444444 1000000
```

Sent from any account other than `<relayer>`, the cook reverts with `WrongSubmitter()`. The submitter is the Pot's immediate caller: through a forwarding contract, it is that contract.

### Cancel a signature

```bash theme={null}
sauce sign --cancel <nonce> --chain base --wallet agent --password-env SAUCE_WALLET_PASSWORD
```

```text theme={null}
invalidateNonces(4332269644…3577, 4503599627370496) on Pot 0x305e21797fAaC092656F3d7aE1D062471625E8c4: cancels nonce 1109061028…5764: 0x6067…d524 success, gas used 45617, block <block>
```

The cancelled signature's cook then reverts with `NonceUsed()`. With `--owner <owner>` instead of a signer, the command prints the `invalidateNonces` call unsigned. On a local fork of Base at block 53116964 with the current contracts, for a deployed Pot, `sauce sign --cancel 12345 --chain base --owner <owner>` printed:

```json theme={null}
{
  "chainId": 8453,
  "pot": "0x9DCA499989B0965700717C28311c427b3aE2A23c",
  "owner": "0x3206c4e288E05961Acd9B668e9cACF45D61810f4",
  "nonces": ["12345"],
  "transactions": [
    { "what": "invalidateNonces(48, 144115188075855872) on Pot 0x9DCA499989B0965700717C28311c427b3aE2A23c: cancels nonce 12345", "chainId": 8453, "to": "0x9DCA499989B0965700717C28311c427b3aE2A23c", "data": "0x2bce68d2…", "value": "0x0", "word": "48", "mask": "144115188075855872" }
  ]
}
```

With `--json`, the same object ends with `"sendCalls": { "chain": "base", "calls": [{ "to": "0x9DCA499989B0965700717C28311c427b3aE2A23c", "value": "0x0", "data": "0x2bce68d2…" }] }`.

### Refusals

A wallet whose policy limits a token:

```text theme={null}
sauce sign: refused by the policy of wallet agent (wallets/agent.policy.json): tokens.USDC is limited, and a signed cook runs when its submitter sends it, any time up to its deadline, on the chain's state then: what it moves cannot be measured when it is signed, nor counted in a day's total. Sign with a wallet whose policy limits only chains and to
```

A preview chain (exit `1`):

```text theme={null}
sauce sign: signing a cook is refused: it involves arbitrum (Arbitrum One, chain id 42161), a preview chain. The sauce command and its MCP server build and send transactions only on Ethereum, Base, Arc and Solana, and the testnets Arc Testnet, Base Sepolia, Ethereum Sepolia, Solana Devnet and Solana Testnet. On a preview chain they build and send none. A program still compiles there and globals, price, pools and pot's prediction still read; simulate runs wherever the release is deployed on the chain, and says so where it is not.
To ask for Arbitrum One: …
```

Solana (exit `2`):

```text theme={null}
sauce sign: signed cooks are the EVM Pot's (Pot.cookSigned): on Solana the owner signs the cook transaction itself, and any fee payer may sponsor it (sauce tx's feePayer)
```

## Next steps

* [Pot](https://docs.eco.com/sauce/pot.md#signed-cooks): what the Pot checks for a signed cook.
* [Security considerations](https://docs.eco.com/sauce/security-considerations.md#signed-cooks): replay, deadlines, the submitter and the fee ceiling.
* [`sauce send`](https://docs.eco.com/sauce-sdk/cli/send): broadcast the transactions a signer signed.
* [Cook transactions](https://docs.eco.com/sauce-sdk/typescript/cook-transactions.md#signed-cooks): the same in TypeScript.
* [MCP tools](https://docs.eco.com/sauce-sdk/mcp/tools.md#sauce_signed_cook): `sauce_signed_cook` and `sauce_sign`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.