> ## 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.

# Actions

> Validate and compile JSON actions documents from TypeScript, for applications that build protocol operations as data.

An actions document is an ordered list of protocol operations written as JSON: swap on a Uniswap V3 pool, approve a token, supply to Aave. `@eco-incorp/sauce/actions` validates a document and compiles it, for one chain, into one Sauce program that runs in a Pot in one transaction. Any language that writes JSON can produce one, and the package publishes the JSON Schema it is checked against.

The same documents run from the command line with [`sauce actions`](https://docs.eco.com/sauce-sdk/cli/actions), and `sauce compile`, `simulate`, `tx` and `run` take one wherever they take a program file.

## The document

```json swap-supply.json theme={null}
{
  "version": 1,
  "actions": [
    { "type": "argument", "name": "amount" },
    {
      "type": "uniswapV3Swap",
      "tokenIn": "USDC",
      "tokenOut": "WETH",
      "factory": "UniswapV3.Factory",
      "fee": 500,
      "amountOutMin": "1",
      "recipient": "pot",
      "saveOutputAs": "weth"
    },
    { "type": "approve", "token": "WETH", "spender": "AaveV3.Pool" },
    {
      "type": "aaveV3Supply",
      "pool": "AaveV3.Pool",
      "token": "WETH",
      "onBehalfOf": "pot",
      "amountRef": "weth"
    }
  ]
}
```

This takes an amount of USDC as a run-time argument, swaps it for WETH in the pool Uniswap V3's factory keys at 0.05%, approves Aave's pool for the WETH received, and supplies it with the Pot as the beneficiary.

| Field | Type | Meaning |
| - | - | - |
| `version` | `1` | The format version. |
| `chainId` | integer, optional | The one chain the document is written for. Compiling it for another chain is refused. Leave it out and the document compiles for any chain where its names exist. |
| `actions` | array, at least one | The actions, in execution order. Each is an object whose `type` selects its fields. |

A `$schema` key is allowed and ignored. Every action runs in one transaction on the chain the document is compiled for; a bridge's destination is one of the bridge action's own fields.

### Values

| Value | Encoding |
| - | - |
| Amounts, prices, fees, strategy ids | A base-10 string with no sign, exponent or leading zeros: `"1000000"`. A JSON number is refused. |
| Tokens (`tokenIn`, `token`, `path`, …) | A registry symbol (`"USDC"`) or an address; `"native"` where the venue trades the native coin itself. |
| Protocol contracts (`pool`, `vault`, `factory`, `spender`, …) | A namespace reference (`"UniswapV3.Factory"`, `"AaveV3.Pool"`) or an address. |
| Recipients on this chain (`recipient`, `onBehalfOf`, `owner`) | An address, or `"pot"` for the executing Pot. |
| Addresses | `0x` and 40 hex digits. Mixed case must be a valid EIP-55 checksum. |
| Fee tiers, indices, domains, Unix times | JSON integers. |

Each amount must also fit the field it becomes; a value too wide for it is an error.

### Names and addresses

A name lowers to the program global of that name, and the compile for a chain resolves it there, as it resolves `USDC` in a hand-written program. A document with only names and no `chainId` therefore compiles for every chain that has those names, each time to that chain's addresses. An address means the same address on every chain, which suits a contract deployed at one address everywhere, such as Permit2. A document may mix names and addresses.

A swap may name its pool by its factory's key instead of its address: `uniswapV2Swap` by `factory`, `uniswapV3Swap` by `factory` with `fee` (or `tickSpacing` for Aerodrome Slipstream), `traderJoeLBSwap` by `factory` with `binStep`. The program reads the pool from the factory when it runs and reverts before anything moves if there is none.

### Chaining outputs

An action that spends an amount takes it from, in order:

1. its own `amount`;
2. `amountRef`, the name of an output an earlier action saved with `saveOutputAs`;
3. otherwise, the previous action's output.

Setting both `amount` and `amountRef`, naming an output no earlier action saved, or a first action with no amount is an error. Saving a second output under one name reassigns it. An action's output is what it delivered to the Pot (`received`), the amount it spent (`its amount`), or, for `balanceOf`, `nativeBalance` and `argument`, the value read. When a later action spends an output, the action delivers it to the Pot whatever its `recipient` says; an output nothing spends goes to the action's `recipient`.

An `argument` action declares a run-time parameter: it becomes a `Uint256` parameter of `main`, so one compiled program serves every amount, and the value travels as an ABI-v1 word after the bytecode.

## parseProgram

Validates a document and returns a canonical copy.

### Import

```ts theme={null}
import { parseProgram } from "@eco-incorp/sauce/actions";
```

### Usage

```ts parse-errors.mts theme={null}
import { ProgramError, compileProgram, parseProgram } from "@eco-incorp/sauce/actions";

// Two mistakes: a lower-case symbol, and an amount written as a JSON number.
try {
  parseProgram({
    version: 1,
    actions: [{ type: "transfer", token: "usdc", amount: 1000000, recipient: "pot" }],
  });
} catch (error) {
  if (!(error instanceof ProgramError)) throw error;
  for (const issue of error.issues) console.log(`${issue.path}: ${issue.message}`);
}

// A valid document whose name the chain lacks: refused for that chain, which `chain` names.
try {
  compileProgram(
    { version: 1, actions: [{ type: "approve", token: "USDC", spender: "AaveV3.Pool", amount: "1" }] },
    { chain: "kava" },
  );
} catch (error) {
  if (!(error instanceof ProgramError)) throw error;
  console.log(error.chain?.slug, error.issues.map((issue) => issue.path));
  console.log(error.message);
}
```

```text theme={null}
actions[0].token: expected a registry token symbol ("USDC") or an address (0x + 40 hex digits), got "usdc" — symbols are upper case: did you mean "USDC"?
actions[0].amount: expected a base-10 string, got the JSON number 1000000 — JSON numbers lose precision above 2^53, so amounts are strings: write "1000000"
kava [ 'actions[0].token', 'actions[0].spender' ]
the action program does not compile for Kava (kava, chain 2222) (2 issues):
  actions[0].token: no token "USDC" on Kava (chain 2222), which registers no token symbols — give its address there instead
  actions[0].spender: no "AaveV3.Pool" on Kava (chain 2222): AaveV3 is not deployed there (it is on ethereum, optimism, bsc, polygon, base, arbitrum, gnosis, fantom, metis, avalanche, scroll, monad) — give the contract's address there instead
```

### Signature

```ts theme={null}
export declare function parseProgram(input: unknown): ActionProgram;
```

### Parameters

* `input`: the document as JSON text, or an already-parsed value.

### Returns

`ActionProgram`: a fresh copy with its keys in canonical order. It fills in nothing: an optional field left out stays out. Parsing checks how each name is spelled; whether a name exists is decided by the chain the document is compiled for.

### Throws

`ProgramError`, listing every problem at once, each with its path.

## serializeProgram

Writes a document as canonical JSON.

### Import

```ts theme={null}
import { serializeProgram } from "@eco-incorp/sauce/actions";
```

### Usage

```ts serialize.mts theme={null}
import { parseProgram, serializeProgram, type ActionProgram } from "@eco-incorp/sauce/actions";

const program: ActionProgram = {
  actions: [{ recipient: "pot", token: "USDC", type: "transfer", amount: "1000000" }],
  version: 1,
};

const text = serializeProgram(program, 2); // validated, keys in schema order
console.log(text);
console.log(serializeProgram(parseProgram(text)) === serializeProgram(program));
```

```text theme={null}
{
  "version": 1,
  "actions": [
    {
      "type": "transfer",
      "amount": "1000000",
      "token": "USDC",
      "recipient": "pot"
    }
  ]
}
true
```

### Signature

```ts theme={null}
export declare function serializeProgram(program: ActionProgram, space?: number | string): string;
```

### Parameters

* `program`: the document.
* `space`: indentation, as `JSON.stringify` takes it. Default none.

### Returns

The canonical JSON text: two equal programs serialize to the same text, and `parseProgram(serializeProgram(p))` equals `p`.

### Throws

`ProgramError` when `program` is invalid; it is validated first.

## programSchema

Returns the JSON Schema (draft 2020-12) every document satisfies.

### Import

```ts theme={null}
import { programSchema } from "@eco-incorp/sauce/actions";
```

The same schema ships as a file: `@eco-incorp/sauce/actions/action-program.schema.json`.

### Usage

```ts schema.mts theme={null}
import { readFileSync } from "node:fs";
import { programSchema } from "@eco-incorp/sauce/actions";

const schema = programSchema();
console.log(schema.$schema, schema.$id, schema.required);

// The same document, as a file in the package, for a validator outside TypeScript.
const file = import.meta.resolve("@eco-incorp/sauce/actions/action-program.schema.json");
const onDisk = JSON.parse(readFileSync(new URL(file), "utf8"));
console.log(JSON.stringify(onDisk) === JSON.stringify(schema));
```

```text theme={null}
https://json-schema.org/draft/2020-12/schema urn:eco-incorp:sauce:action-program:1 [ 'version', 'actions' ]
true
```

### Signature

```ts theme={null}
export type JsonSchema = {
    readonly [key: string]: unknown;
};
export declare function programSchema(): JsonSchema;
```

### Returns

The schema object. It is generated from the table the parser reads, so a document the schema rejects is always rejected by `parseProgram`. It marks which fields take a token (`$defs/token`, `$defs/tokenOrNative`), a protocol contract (`$defs/contract`) or either (`$defs/tokenContract`), and states each swap's pool alternatives as a `oneOf`.

The schema cannot express four rules that the parser and the compile enforce: EIP-55 checksums, exact numeric ranges (it bounds digit counts), the chaining rules, and whether a name exists on the chain being compiled for. Validate with the schema at the edge of your system, and parse before compiling.

## compileProgram

Compiles a document for one chain into a program and its cook payload.

### Import

```ts theme={null}
import { compileProgram } from "@eco-incorp/sauce/actions";
```

### Usage

```ts compile-actions.mts theme={null}
import { readFileSync } from "node:fs";
import { compileProgram, parseProgram } from "@eco-incorp/sauce/actions";

const program = parseProgram(readFileSync("swap-supply.json", "utf8"));
const compiled = compileProgram(program, { chain: "base" });

console.log(compiled.source);
console.log("parameters:", compiled.parameters);
console.log("bytecode:", compiled.bytecode.length, "bytes");

// The `program` argument of Pot.cook, for 1,000 USDC: bytecode, then the encoded `amount`.
const payload = compiled.payload({ amount: 1_000_000_000n });
console.log("payload:", payload.length, "bytes; amount at offset", compiled.argumentOffset("amount"));
```

```text theme={null}
import { uniswapV3 } from "@sauce/router";

function main(a_amount: Uint256): void {
  let t_out0 = a_amount;
  const pool0 = UniswapV3.Factory.getPool(USDC, WETH, 500);
  require(pool0 != 0, "actions[1]: no pool under that key");
  const amt1 = uniswapV3(pool0, USDC, WETH, t_out0, 0, 1, pot);
  let v_weth = amt1;
  // … 17 lines: WETH's allowance for AaveV3.Pool read, reset to zero if set, then set to v_weth,
  // each write checked as SafeERC20 checks it …
  IAaveV3Pool.at(AaveV3.Pool).supply(WETH, v_weth, pot, 0);
}

parameters: [ 'amount' ]
bytecode: 895 bytes
payload: 927 bytes; amount at offset 895
```

The swap is a call into [`@sauce/router`](https://docs.eco.com/sauce-libraries/router), the same library a hand-written program calls. The lowered program names the Pot `pot` and its native balance `pot.balance`, as a hand-written one does; a split swap compiled with no `chain` writes `ctx.self()`. Every other action is an ABI-bound call, `IBinding.at(address).method(...)`, with the registry's ABI wherever the registry declares the exact function. Reading any part of a bound call's result decodes all its declared outputs; a result the program discards is neither decoded nor checked. ERC-20 `transfer` and `approve` are checked writes with OpenZeppelin `SafeERC20` semantics. A call that carries native value (`wrapETH`, the staking deposits, the bridge fees) is a raw `evm.call`.

### Signature

```ts theme={null}
export declare function compileProgram(program: ActionProgram, options?: CompileOptions): CompiledProgram;

export interface CompileOptions {
    readonly chain?: ChainRef;
}

export interface CompiledProgram {
    readonly bytecode: Uint8Array;
    readonly source: string;
    readonly contracts: ActionContracts;
    readonly parameters: readonly string[];
    readonly entryEncoding: "abi-v1";
    payload(values?: ArgumentValues): Uint8Array;
    argumentOffset(name: string): number;
}

export type ArgumentValues = Readonly<Record<string, bigint | number | string>>;
```

### Parameters

* `program`: the document. It is validated again, so a typed document that skipped `parseProgram` is held to the same rules.
* `options.chain`: the chain to compile for, a slug (`"base"`), a chain id (`8453`) or a `CanonicalChain`. Defaults to the document's `chainId`; a document without one needs it.

### Returns

`CompiledProgram`:

* `bytecode`: the compiled program.
* `source`: the SauceScript the document lowered to, with every name as written.
* `contracts`: the ABI bindings `source` calls through.
* `parameters`: the `argument` names, in the order `main` takes them.
* `entryEncoding`: always `"abi-v1"`, the only argument encoding.
* `payload(values?)`: the bytecode followed by the encoded arguments, by name: the `program` a Pot's `cook(engine, program)` takes ([Cook transactions](https://docs.eco.com/sauce-sdk/typescript/cook-transactions.md)).
* `argumentOffset(name)`: where argument `name`'s 32-byte big-endian word starts in the payload. The offset is fixed whatever the values, so a number measured later can be spliced into a payload built earlier.

### Throws

`ProgramError` when the document is invalid, when `chainId` names another chain, or when a name does not exist on the chain, listing every such name with its path.

The SDK refuses on Arc (chain 5042) what Arc cannot do: `wrapETH`, `unwrapETH`, `lidoStake`, `rocketPoolStake`, `etherFiStake`, `balancerV3Swap` with `wethIsEth: true`, and a `nativeBalance` spent as a token amount. Arc's native coin is USDC, the same balance as its USDC ERC-20 ([Arc](https://docs.eco.com/sauce-sdk/reference/chains/arc.md)).

## ProgramError

The error every function on this page throws for a document that breaks a rule.

### Import

```ts theme={null}
import { ProgramError } from "@eco-incorp/sauce/actions";
```

### Usage

The [`parseProgram` example](#parseprogram) catches it twice.

### Signature

```ts theme={null}
export interface ProgramIssue {
    readonly path: string;
    readonly message: string;
}
export declare class ProgramError extends Error {
    readonly issues: readonly ProgramIssue[];
    readonly chain?: CanonicalChain;
    constructor(issues: readonly ProgramIssue[], chain?: CanonicalChain);
}
```

### Properties

* `issues`: every problem found, in order, each located by a path into the document (`actions[2].amountRef`).
* `chain`: set when the issues are the compiled chain's, such as a name it lacks, rather than the document's own.
* `message`: a summary line, then one line per issue.

## quoteAction

Builds the `eth_call` that prices a swap action at its own `amount`. It reads nothing; you send the call.

[`@sauce/router`](https://docs.eco.com/sauce-libraries/router) has no quote function, so this is how TypeScript prices a swap before it builds a program. A program can also read a quote itself before it swaps, as [Quote, swap and supply](https://docs.eco.com/quickstarts/sauce/quote-swap-supply.md) does.

### Import

```ts theme={null}
import { quoteAction } from "@eco-incorp/sauce/actions";
```

### Usage

```ts quote.mts theme={null}
import { quoteAction, type UniswapV3SwapAction } from "@eco-incorp/sauce/actions";
import { v12QuoteRouterAddress } from "@eco-incorp/sauce/deployments";
import { createPublicClient, getAddress, http } from "viem";
import { base } from "viem/chains";

const rpcUrl = process.argv[2]; // your Base JSON-RPC URL: the SDK ships none
const client = createPublicClient({ chain: base, transport: http(rpcUrl) });

const swap: UniswapV3SwapAction = {
  type: "uniswapV3Swap",
  pool: "0xd0b53D9277642d899DF5C87A3966A349A798F224", // Uniswap V3 WETH/USDC 0.05% on Base
  tokenIn: "USDC",
  tokenOut: "WETH",
  amount: "1000000000", // 1,000 USDC
  amountOutMin: "1",
  recipient: "pot",
};

const quote = quoteAction(swap, { chain: "base", router: getAddress(v12QuoteRouterAddress()) });
const blockNumber = await client.getBlockNumber();
const { data } = await client.call({ to: quote.to, data: quote.data, blockNumber });
if (data === undefined) throw new Error("the quote returned nothing");

console.log("block", blockNumber, "WETH out:", quote.decode(data));
```

```bash theme={null}
node quote.mts <your Base RPC URL>
```

On Base at block 53157152, through a public endpoint:

```text theme={null}
block 53157152n WETH out: 431160687887827317n
```

### Signature

```ts theme={null}
export declare function quoteAction(action: SwapAction, options?: QuoteOptions): Quote;

export interface Quote {
    readonly to: Address;
    readonly data: Hex;
    decode(result: Hex): bigint;
}

export interface QuoteOptions {
    readonly chain?: ChainRef;
    readonly router?: Address;
    readonly maverickQuoter?: Address;
    readonly ambientImpact?: Address;
    readonly fluidDexResolver?: Address;
}
```

### Parameters

* `action`: a swap action with its `amount` (a Carbon trade or a Balancer batch prices at the amounts it carries). Its pool must be given by address.
* `options.chain`: the chain whose names the action's tokens and contracts resolve to; required when the action uses a name.
* `options.router`: for `uniswapV3Swap` and `uniswapV4Swap`, the quote Router at `v12QuoteRouterAddress()` from `@eco-incorp/sauce/deployments` ([Deployments](https://docs.eco.com/sauce-sdk/reference/deployments.md)). The content-addressed execution Router at `v12RouterAddress()`, which a Pot swaps through, has no quote method.
* `options.maverickQuoter`, `options.ambientImpact`, `options.fluidDexResolver`: the quoter for `maverickV2Swap`, `ambientSwap` and `fluidDexT1Swap`.

The other venues price on the contract the action names: a Uniswap V2 pair's reserves, a Curve pool's `get_dy`, a DODO pool's `querySellBase` or `querySellQuote`, a Trader Joe pair's `getSwapOut` (zero when the pair cannot take the whole input), WooPPV2's `query`. Send a Balancer V3 quote from the zero address. No quote needs a balance or an allowance.

### Returns

`Quote`: send `data` to `to` as an `eth_call`, and pass the result to `decode` for the output amount in `tokenOut`'s smallest unit.

### Throws

For a pool given by key: read the pool from the factory first, then give `pool`. For an action that names a token or contract when `options.chain` is missing.

## compileSplitSwap

Compiles one program that divides an amount into equal slices and gives each, in turn, to the candidate pool whose onchain quote pays the most for it, then executes every candidate's share.

### Import

```ts theme={null}
import { compileSplitSwap } from "@eco-incorp/sauce/actions";
```

### Usage

```ts split-swap.mts theme={null}
import { compileSplitSwap } from "@eco-incorp/sauce/actions";
import { v12QuoteRouterAddress } from "@eco-incorp/sauce/deployments";
import { getAddress } from "viem";

// 1,000 USDC for WETH, in 10 slices, each to whichever Base pool quotes the most for it.
const split = compileSplitSwap({
  chain: "base",
  amount: "1000000000",
  buckets: 10,
  amountOutMin: "400000000000000000", // 0.4 WETH across every leg
  candidates: [
    {
      type: "uniswapV3Swap",
      pool: "0xd0b53D9277642d899DF5C87A3966A349A798F224", // Uniswap V3 0.05%
      tokenIn: "USDC",
      tokenOut: "WETH",
      amountOutMin: "0",
      recipient: "pot",
    },
    {
      type: "uniswapV3Swap",
      pool: "0x6c561B446416E1A00E8E93E221854d6eA4171372", // Uniswap V3 0.3%
      tokenIn: "USDC",
      tokenOut: "WETH",
      amountOutMin: "0",
      recipient: "pot",
    },
  ],
  quoters: { router: getAddress(v12QuoteRouterAddress()) },
  sweep: { token: "WETH", recipient: "0x1111111111111111111111111111111111111111" },
});

console.log("bytecode:", split.bytecode.length, "bytes; parameters:", split.parameters);
```

```text theme={null}
bytecode: 1638 bytes; parameters: []
```

### Signature

```ts theme={null}
export declare function compileSplitSwap(swap: SplitSwap): CompiledProgram;

export interface SplitSwap {
    readonly candidates: readonly SwapAction[];
    readonly amount: string;
    readonly buckets: number;
    readonly amountOutMin: string;
    readonly approvals?: readonly ApproveAction[];
    readonly sweep?: {
        readonly token: Token;
        readonly recipient: Recipient;
    };
    readonly quoters?: QuoteOptions;
    readonly chain?: ChainRef;
}
```

### Parameters

* `candidates`: ordinary swap actions with no `amount`, `amountRef` or `saveOutputAs`, each with its pool by address (a `uniswapV4Swap` by its `poolManager` and key) and each delivering to the Pot. Each must have an onchain quote with a fixed amount offset: every venue but Balancer (V2, its batch swap and V3) and Carbon, which the split refuses (`candidates[i] (balancerV2Swap) has no on-chain quote with a runtime amount, which a split needs`). Uniswap V3 and V4 candidates quote through `quoters.router`, the quote Router at `v12QuoteRouterAddress()`.
* `amount`: the total input, a base-10 string divisible by `buckets`.
* `buckets`: how many equal slices the allocation hands out; at least 1.
* `amountOutMin`: the least total output, checked once after every leg. Required; `"0"` waives it.
* `approvals`: approvals to run first, each with an explicit `amount`, for a candidate that pulls through a periphery contract. A `@sauce/router` swap needs none.
* `sweep`: sends the total output of `token` to `recipient` at the end; omit it to keep the output in the Pot. `recipient` is an address or `"pot"`.
* `quoters`: the quoter contracts the candidates price through, as in `quoteAction`.
* `chain`: the chain the names in the candidates, approvals and sweep resolve on; needed only when they use a name.

### Returns

A `CompiledProgram` with no run-time arguments: its `payload()` is the bytecode.

### Throws

`ProgramError` for an invalid candidate or a name the chain lacks; an error for a pool given by key.

## Action reference

Every action type, generated from `@eco-incorp/sauce/actions/action-program.schema.json`. Every action that takes `amount` also takes `amountRef`, and every action takes `saveOutputAs`. Output is what a later action spends.

| Action | Required | Optional | Takes `amount` | Output |
| - | - | - | - | - |
| `uniswapV2Swap` | `tokenIn`, `tokenOut`, `amountOutMin`, `recipient`; `pool` or `factory` | `feePpm` | yes | received |
| `uniswapV3Swap` | `tokenIn`, `tokenOut`, `amountOutMin`, `recipient`; `pool` or `factory` + `fee` or `factory` + `tickSpacing` | `sqrtPriceLimitX96` | yes | received |
| `uniswapV4Swap` | `poolManager`, `tokenIn`, `tokenOut`, `fee`, `tickSpacing`, `amountOutMin`, `recipient` | `hooks`, `sqrtPriceLimitX96` | yes | received |
| `curveSwap` | `pool`, `tokenIn`, `tokenOut`, `i`, `j`, `indexType`, `amountOutMin`, `recipient` | | yes | received |
| `balancerV2Swap` | `vault`, `poolId`, `tokenIn`, `tokenOut`, `amountOutMin`, `recipient` | | yes | received |
| `dodoV2Swap` | `pool`, `tokenIn`, `tokenOut`, `baseToken`, `quoteToken`, `amountOutMin`, `recipient` | | yes | received |
| `traderJoeLBSwap` | `tokenIn`, `tokenOut`, `amountOutMin`, `recipient`; `pool` or `factory` + `binStep` | `tokenX`, `tokenY` | yes | received |
| `woofiSwap` | `pool`, `tokenIn`, `tokenOut`, `amountOutMin`, `recipient` | | yes | received |
| `maverickV2Swap` | `pool`, `tokenIn`, `tokenOut`, `amountOutMin`, `recipient` | | yes | received |
| `curveRouterNGSwap` | `router`, `route`, `swapParams`, `pools`, `amountOutMin`, `recipient` | | yes | received |
| `balancerV2BatchSwap` | `vault`, `steps`, `assets`, `amountOutMin`, `recipient`, `deadline` | | no | received |
| `balancerV3Swap` | `router`, `pool`, `tokenIn`, `tokenOut`, `amountOutMin`, `deadline`, `wethIsEth` | | yes | received |
| `ambientSwap` | `dex`, `base`, `quote`, `poolIdx`, `isBuy`, `inBaseQty`, `tip`, `limitPrice`, `amountOutMin`, `reserveFlags` | | yes | received |
| `dodoV1Swap` | `proxy`, `tokenIn`, `tokenOut`, `pairs`, `directions`, `amountOutMin`, `deadline` | | yes | received |
| `carbonSwap` | `controller`, `sourceToken`, `targetToken`, `tradeActions`, `amountOutMin`, `deadline` | | no | received |
| `fraxswapSwap` | `router`, `path`, `amountOutMin`, `recipient`, `deadline` | | yes | received |
| `fluidDexT1Swap` | `pool`, `swap0to1`, `amountOutMin`, `recipient` | | yes | received |
| `acrossBridge` | `spokePool`, `token`, `destChainId`, `recipient`, `relayerFee`, `quoteTimestamp`, `fillDeadline`, `exclusivityDeadline`, `message` | | yes | its amount |
| `stargateBridge` | `pool`, `dstEid`, `recipient`, `amountOutMin` | | yes | its amount |
| `cctpBridge` | `tokenMessenger`, `token`, `destinationDomain`, `recipient` | `maxFee`, `minFinalityThreshold` | yes | its amount |
| `hyperlaneBridge` | `router`, `destinationDomain`, `recipient` | | yes | its amount |
| `wrapETH` | `weth` | | yes | its amount |
| `unwrapETH` | `weth` | | yes | its amount |
| `wrapStETH` | `wstETH` | | yes | received |
| `unwrapStETH` | `wstETH` | | yes | received |
| `lidoStake` | `stETH` | `referral` | yes | received |
| `lidoUnstake` | `withdrawalQueue`, `owner` | | yes | its amount |
| `rocketPoolStake` | `depositPool`, `rETH` | | yes | received |
| `rocketPoolUnstake` | `rETH` | | yes | received |
| `etherFiStake` | `liquidityPool`, `eETH` | | yes | received |
| `aaveV3Supply` | `pool`, `token`, `onBehalfOf` | `referralCode` | yes | its amount |
| `aaveV3Withdraw` | `pool`, `token`, `recipient` | | yes | received |
| `aaveV3Borrow` | `pool`, `token`, `onBehalfOf` | `referralCode` | yes | its amount |
| `aaveV3Repay` | `pool`, `token`, `onBehalfOf` | | yes | its amount |
| `compoundV3Supply` | `comet`, `token` | | yes | its amount |
| `compoundV3Withdraw` | `comet`, `token` | | yes | its amount |
| `transfer` | `token`, `recipient` | | yes | its amount |
| `approve` | `token`, `spender` | | yes | its amount |
| `permit2Approve` | `permit2`, `token`, `spender`, `expiration` | | yes | its amount |
| `balanceOf` | `token` | | no | the value read |
| `nativeBalance` | | | no | the value read |
| `argument` | `name` | | no | the value read |

Each field's documentation is its `description` in the schema. A `@sauce/router` swap (the first nine rows) needs no approval: it pushes its input to the pool, approves exactly its input itself, or the Pot's Router pays the pool. Any other venue that pulls from the Pot needs an `approve` first.

## TypeScript types

Every type is the JSON it describes, with amounts as strings and no class instances.

* `ActionProgram` is the document, `Action` the union of every action, and `ActionType` its `type`.
* Each action has its own type (`UniswapV3SwapAction`, `AaveV3SupplyAction`, …), grouped as `SwapAction` (with `RouterSwapAction`, the nine `@sauce/router` swaps), `BridgeAction`, `WrapAction`, `StakeAction`, `LendingAction`, `TokenAction` and `SourceAction`.
* A field's type says what it takes: `Token` (a `TokenSymbol` or an address), `TokenOrNative`, `Contract` (a `ContractName`, `"Namespace.Contract"`, or an address), `TokenContract` and `Recipient` (`` `0x${string}` | "pot" ``).
* A swap that names its pool by key is a union, so TypeScript refuses the mixes the parser refuses: `UniswapV3SwapAction` is a pool, or a factory with a fee, or a factory with a tick spacing.

## Next steps

* [`sauce actions`](https://docs.eco.com/sauce-sdk/cli/actions): print what a document lowers to from the command line.
* [`@sauce/router`](https://docs.eco.com/sauce-libraries/router): the swap library the swap actions call.
* [Cook transactions](https://docs.eco.com/sauce-sdk/typescript/cook-transactions.md): wrap a payload in `Pot.cook`.
* [Actions: swap and supply](https://docs.eco.com/quickstarts/sauce/actions-swap-supply.md): a worked document.


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