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

# Entry arguments

> Encode and decode a program's main arguments in ABI-v1, and append them to the bytecode a cook runs.

A program takes its inputs as `main`'s typed parameters. The compiled bytecode holds no values for them: each cook appends the encoded arguments to the bytecode, and that whole payload is the `program` argument of `Pot.cook(engine, program)`. One compiled program serves every set of values.

```text theme={null}
program = bytecode ‖ encoded arguments
```

There is no function selector: the program reads its arguments from the bytes after its own code. The encoding is ABI-v1, the only one: a compiled program's `entryEncoding` is always `"abi-v1"`. To fix the values in the bytecode instead, pass `args` when compiling; see [Bind arguments at compile time](https://docs.eco.com/sauce-sdk/typescript/compiling.md#bind-arguments-at-compile-time).

## routes.encodeEntryArguments

Checks values against `main`'s declared parameters, in order, and encodes them in the layout `main` reads.

### Import

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

### Usage

```ts entry-args.ts theme={null}
import { routes } from "@eco-incorp/sauce";
import { bytesToHex, concatHex } from "viem";

const source = `
function main(to: Address, amount: Uint256) {
  require(pot.USDC >= amount, "not enough USDC");
  USDC.transfer(to, amount);
}
`;

const program = routes.compileSauceProgram("base", source);

const args = routes.encodeEntryArguments(program, [
  "0x2222222222222222222222222222222222222222",
  1_000_000n, // 1 USDC: 6 decimals
]);
const payload = concatHex([bytesToHex(program.bytecode), bytesToHex(args)]);

console.log("arguments:", args.length, "bytes");
console.log("payload:", (payload.length - 2) / 2, "bytes");
console.log("decoded:", routes.decodeEntryArguments(program, args));
```

```text theme={null}
arguments: 64 bytes
payload: 287 bytes
decoded: [ '0x2222222222222222222222222222222222222222', 1000000n ]
```

The payload is the 223-byte program followed by its 64 bytes of arguments. [Cook transactions](https://docs.eco.com/sauce-sdk/typescript/cook-transactions.md) sends it.

### Signature

```ts theme={null}
function encodeEntryArguments(program: ProgramEntry, values: readonly EntryValue[]): Uint8Array;

type ProgramEntry = Pick<CompiledSauceProgram, "entryEncoding" | "entryParams">;

type EntryValue =
  | bigint
  | number
  | boolean
  | string
  | Uint8Array
  | readonly EntryValue[]
  | { readonly [field: string]: EntryValue };
```

### Parameters

| Parameter | Type | Meaning |
| - | - | - |
| `program` | `ProgramEntry` | A program from `routes.compileSauceProgram`, or any object with its `entryEncoding` and `entryParams` |
| `values` | `readonly EntryValue[]` | One value per entry parameter, in declaration order |

A value takes the form of its parameter's type:

| Parameter type | Value |
| - | - |
| `Uint256` and other unsigned integers | A `bigint`, a safe-integer `number`, or a string of digits |
| `Int256` | A `bigint`, a safe-integer `number`, or a string of digits, from -2^255 through 2^255 - 1. A negative value is written as it is: `-10n` |
| `Address` | 20 bytes of `0x`-prefixed hex |
| `bool` | A `boolean` |
| `bytes` | A `Uint8Array` or hex |
| An array | An array of values |
| A record (tuple) | An array of its fields in order, or an object naming them |

### Returns

`Uint8Array`: the encoded arguments, to append to the program's bytecode.

### Throws

A wrong number of values throws a `RangeError`; a value that is not of its parameter's type throws a `TypeError` naming the parameter:

```ts entry-args-error.ts theme={null}
import { routes } from "@eco-incorp/sauce";

const program = routes.compileSauceProgram(
  "base",
  "function main(to: Address, amount: Uint256) {\n  USDC.transfer(to, amount);\n}\n",
);

for (const values of [[1_000_000n], ["0x22", 1_000_000n], ["0x2222222222222222222222222222222222222222", -1n]]) {
  try {
    routes.encodeEntryArguments(program, values);
  } catch (error) {
    if (!(error instanceof Error)) throw error;
    console.log(`${error.name}: ${error.message}`);
  }
}

const args = routes.encodeEntryArguments(program, ["0x2222222222222222222222222222222222222222", 1n]);
try {
  routes.decodeEntryArguments(program, new Uint8Array([...args, 0]));
} catch (error) {
  if (!(error instanceof Error)) throw error;
  console.log(`${error.name}: ${error.message}`);
}
```

```text theme={null}
RangeError: main takes 2 arguments (to: Address, amount: Uint256), got 1
TypeError: argument 1 (to: Address): '0x22' is not an address: 20 bytes of 0x-prefixed hex
TypeError: argument 2 (amount: Uint256): -1n is not an unsigned integer below 2^256 (a bigint, a safe integer, or its digits)
RangeError: decodeEntryArguments: 65 bytes are not the canonical encoding of main's arguments (they re-encode to 64 bytes)
```

## routes.decodeEntryArguments

The strict inverse of `encodeEntryArguments`: reads `main`'s arguments back from the bytes appended to the program.

### Import

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

### Usage

`entry-args.ts` above decodes the arguments it encoded:

```ts theme={null}
console.log("decoded:", routes.decodeEntryArguments(program, args));
```

### Signature

```ts theme={null}
function decodeEntryArguments(program: ProgramEntry, encoded: Uint8Array): EntryValue[];
```

### Parameters

| Parameter | Type | Meaning |
| - | - | - |
| `program` | `ProgramEntry` | The compiled program the arguments belong to |
| `encoded` | `Uint8Array` | The argument bytes, without the bytecode in front of them |

### Returns

`EntryValue[]`: one value per declared parameter. Integers come back as `bigint`, an `Int256` with its sign, addresses as hex, records as objects naming their fields.

### Throws

A `RangeError` when `encoded` is not exactly the encoding `encodeEntryArguments` produces for the values it decodes to: truncated, padded or otherwise non-canonical bytes. The last line of the `entry-args-error.ts` output above is one.

## Signed integers

An `Int256` parameter is signed. Its word is the two's complement of the value, and it decodes with its sign:

```ts int256-args.ts theme={null}
import { routes } from "@eco-incorp/sauce";

const source = `
function main(delta: Int256, amount: Uint256): Int256 {
  return delta + Int256(amount);
}
`;

const program = routes.compileSauceProgram("base", source);
console.log(program.entryParams);

const args = routes.encodeEntryArguments(program, [-10n, 3n]);
console.log("first word:", Buffer.from(args.slice(0, 32)).toString("hex"));
console.log("decoded:", routes.decodeEntryArguments(program, args));

try {
  routes.encodeEntryArguments(program, [3n, -1n]);
} catch (error) {
  if (!(error instanceof Error)) throw error;
  console.log(`${error.name}: ${error.message}`);
}
```

```text theme={null}
[
  { name: 'delta', type: 'Int256' },
  { name: 'amount', type: 'Uint256' }
]
first word: fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6
decoded: [ -10n, 3n ]
TypeError: argument 2 (amount: Uint256): -1n is not an unsigned integer below 2^256 (a bigint, a safe integer, or its digits)
```

`-10n` is accepted for the `Int256` parameter and refused for the `Uint256` one. A value outside -2^255 through 2^255 - 1 throws a `TypeError` naming the parameter.

## ABI-v1 layout

ABI-v1 is `abi.encode` of `main`'s parameters, with no selector:

```ts entry-args-abi.ts theme={null}
import { routes } from "@eco-incorp/sauce";
import { bytesToHex, encodeAbiParameters } from "viem";

const program = routes.compileSauceProgram(
  "base",
  `function main(amounts: Uint256[], minimum: Uint256): Uint256 {
  let total = 0;
  for (let i = 0; i < amounts.length; i++) {
    total += amounts[i];
  }
  require(total >= minimum, "below minimum");
  return total;
}`,
);

const args = routes.encodeEntryArguments(program, [[25n, 75n], 100n]);
const abi = encodeAbiParameters([{ type: "uint256[]" }, { type: "uint256" }], [[25n, 75n], 100n]);
console.log(args.length, "bytes; same as abi.encode:", bytesToHex(args) === abi);
```

```text theme={null}
160 bytes; same as abi.encode: true
```

A record parameter of fixed size is the exception. `main` reads each parameter from one 32-byte head word, so such a record sits behind an offset word, as a dynamic parameter would. `abi.encode` writes its fields inline. The raw compiler marks it `indirect` in `entryParams`:

```ts entry-args-tuple.ts theme={null}
import { routes } from "@eco-incorp/sauce";
import { compile } from "@eco-incorp/sauce/compiler";
import { encodeAbiParameters, bytesToHex } from "viem";

const source = `
interface Leg {
  amount: Uint256;
  to: Address;
}

function main(leg: Leg, legs: Leg[]): Uint256 {
  return leg.amount + legs.length;
}
`;

const artifact = compile({ target: "evm", resolve: () => new TextEncoder().encode(source) });
console.log(artifact.entryParams.map((p) => `${p.name}: ${p.type}${p.indirect ? " (indirect)" : ""}`));

const leg = { amount: 5n, to: "0x2222222222222222222222222222222222222222" } as const;
const values = [leg, [leg, leg]] as const;

const inline = encodeAbiParameters(artifact.entryParams, values);
const program = routes.compileSauceProgram("base", source);
const args = bytesToHex(routes.encodeEntryArguments(program, values));

console.log("encodeAbiParameters:", (inline.length - 2) / 2, "bytes; first word", inline.slice(0, 66));
console.log("encodeEntryArguments:", (args.length - 2) / 2, "bytes; first word", args.slice(0, 66));
```

```text theme={null}
[ 'leg: tuple (indirect)', 'legs: tuple[]' ]
encodeAbiParameters: 256 bytes; first word 0x0000000000000000000000000000000000000000000000000000000000000005
encodeEntryArguments: 288 bytes; first word 0x0000000000000000000000000000000000000000000000000000000000000040
```

`encodeEntryArguments` starts with the offset word `0x40`; `encodeAbiParameters` starts with the field `amount`. A program given the inline layout reverts with no data: on a local fork of Base at block 52992458 with the current contracts, this program's cook returned `7` with `encodeEntryArguments`'s bytes and reverted with `encodeAbiParameters`'s. Encode a program with an `indirect` parameter with `routes.encodeEntryArguments`.

## Raw compiler arguments

A program from the raw `compile()` carries `entryParams`, its parameters as an ABI parameter list. When no parameter is `indirect`, viem's `encodeAbiParameters(entryParams, values)` is the argument payload as it stands:

```ts raw-entry-params.ts theme={null}
import { routes } from "@eco-incorp/sauce";
import { compile } from "@eco-incorp/sauce/compiler";
import { bytesToHex, decodeAbiParameters, encodeAbiParameters, hexToBytes } from "viem";

const source = "function main(to: Address, amount: Uint256): Uint256 {\n  return amount;\n}\n";
const artifact = compile({ target: "evm", resolve: () => new TextEncoder().encode(source) });

if (artifact.entryParams.some((p) => p.indirect)) throw new Error("encode with routes.encodeEntryArguments");
const values = ["0x2222222222222222222222222222222222222222", 1_000_000n] as const;
const args = hexToBytes(encodeAbiParameters(artifact.entryParams, values));
const program = new Uint8Array([...artifact.bytecode, ...args]);

console.log(JSON.stringify(artifact.entryParams));
console.log("program:", program.length, "bytes");
console.log("decoded:", decodeAbiParameters(artifact.entryParams, bytesToHex(args)));

const sdk = routes.encodeEntryArguments(routes.compileSauceProgram("base", source), values);
console.log("same as routes.encodeEntryArguments:", bytesToHex(sdk) === bytesToHex(args));
```

```text theme={null}
[{"name":"to","type":"address"},{"name":"amount","type":"uint256"}]
program: 108 bytes
decoded: [ '0x2222222222222222222222222222222222222222', 1000000n ]
same as routes.encodeEntryArguments: true
```

Check for `indirect` before you encode with viem, as the example does. A parameter bound with the raw `args` option is not in `entryParams`, so it takes no value. On Solana, `Account` parameters are not in `entryParams` either: they are attached accounts, which the manifest lists.

## Next steps

* [Compiling](https://docs.eco.com/sauce-sdk/typescript/compiling.md): `entryParams`, `entrySignature` and binding arguments with `args`.
* [Cook transactions](https://docs.eco.com/sauce-sdk/typescript/cook-transactions.md): send the payload to a Pot.
* [Bytecode](https://docs.eco.com/sauce/bytecode.md): what the compiled program contains.
* [sauce compile](https://docs.eco.com/sauce-sdk/cli/compile.md) and [sauce tx](https://docs.eco.com/sauce-sdk/cli/tx.md): `--args` encodes the same way from a terminal.


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