Skip to main content
Three functions compile a SauceScript program. They differ in what they resolve and what they return. Compiling reads no network, and the result is the same in Node and in a browser. In a browser, call ready() once first.

routes.compileSauceProgram

Compiles a program for one chain.

Import

Usage

compile-program.ts
The source is a module that declares function main(...), or a script whose top-level statements run as the entry. A script cannot return, so a program that returns a value declares main. The program reads the chain’s names with no import: token symbols (USDC), protocol namespaces (UniswapV3.Factory), chainId, and the @sauce/token functions. One source therefore compiles unchanged for every chain where its names exist.

Signature

Parameters

Returns

CompiledSauceProgram:

Throws

  • An unknown chain: Unknown chain 'not-a-chain' (known slugs: ethereum, optimism, …).
  • A use of a protocol name the chain lacks, outside a test of it: compileSauceRoute: `Aerodrome.Router` is not deployed on ethereum. A contract the chain lacks is zero there, and only a test of it may use it: `if (Aerodrome.Router) { … }` compiles the branch only where the chain has it. It is deployed on base.
  • A compile error, with source locations. See Compile errors.

Bind arguments at compile time

options.args fixes main’s arguments in the bytecode. The result is a different program, specialised to those values, that takes no arguments at run time.
compile-bound.ts
The bound program is not smaller: values fixed at compile time can make it larger. Its entryParams is empty, and its entrySignature still lists both parameters. To compile once and pass values per cook, leave args out and encode the values with routes.encodeEntryArguments. A bound argument binds main’s parameter and nothing else. With args: [5n], this program returned 30005 from a cook on a local fork of Base at block 52991146 with the current contracts: fee() read the module’s FEE, 30, and main read its bound parameter, 5:

Programs that import a library

compileSauceProgram resolves the @sauce/* libraries with no option: @sauce/router, the @sauce/token it imports and the pool ABIs it binds. This compiles the @sauce/router fallback swap, swap-fallback.sauce.ts, for two chains:
router-compile.mts
The same source compiles on each chain to that chain’s USDC, WETH and factories, so the two programs differ. routes.compileSauceRoute and the actions package resolve the libraries the same way; the raw compile resolves them only through resolveSdkModule and resolveSdkPackage, under “The SDK’s modules” below.

routes.compileSauceRoute

Compiles a program and builds the one cook call that runs it on a Pot, in a single step.

Import

Usage

compile-route.ts
source shows the SDK’s rewrite: pot.USDC became a balanceOf call on the chain’s USDC.

Signature

Parameters

On Solana, execution names a staged code account, and the call it builds is not one the released Solana engine accepts. Build Solana cooks with the Kitchen client; see Solana.

Returns

CompiledSauceRoute:
  • calls: one call, { to, target, data, value }. to is the Pot’s checksummed address, target the same Pot as a 32-byte, left-padded address, and value the execution.value you passed, as a bigint.
  • compiled.bytecode: a Uint8Array[] holding one segment, the program.
  • compiled.warnings: always an empty array. A failed compile throws.
  • source: the source after the SDK’s rewrites.

How it differs from compileSauceProgram

  • It takes no run-time arguments: calls carries the bytecode with nothing appended.
  • Its result has no entryParams, entryEncoding, isaRevision or Solana manifest.
  • It supplies no chainId: a program that reads chainId fails to compile with `chainId` is not a declared variable.
  • It supplies no ambient @sauce/token functions. Import them in the program, or pass ambient: ["@sauce/token"]:
compile-route-ambient.ts
Use compileSauceProgram when you need main’s parameters or a Solana manifest.

compile

The raw compiler. It resolves nothing: no chain names, no token syntax, no SDK modules unless your resolver serves them. Use it for full control over modules and compiler settings, for a closure entry, or for the reports of nested programs.

Import

Usage

raw-compile.ts
Compiling is synchronous. The compiler fetches nothing itself: every module and JSON file comes through resolve.

Signature

Parameters

Returns

CompileResult:
  • bytecode: the program, with no argument values in it.
  • isaRevision: the instruction-set label, "stack-v3". It is a label, not a compatibility check: a program runs on the engine release paired with the compiler version the SDK pins, which V12_RELEASE_SETS in /deployments records.
  • entryEncoding: always "abi-v1".
  • entryParams: main’s run-time parameters as an ABI parameter list, in the JSON shape viem and Solidity use. A top-level tuple of fixed size carries indirect: true: main reads it behind an offset word. Entry arguments shows how to encode for it. On Solana, Account parameters are absent; the manifest lists them.
  • entrySignature: main’s parameters in SauceScript’s own type names (Uint256, Int256, Address, records written out), each with its abi entry, and returns, the declared return type. It keeps parameters bound through args and Solana Account parameters.
  • programs: one ProgramReport per closure compiled as a program of its own with program(closure, ...args), inner programs first.
  • manifest: on Solana, the accounts main takes, by index and role. Absent on EVM.
  • chain: the chain option echoed back, when one was given.
On Solana the manifest lists each Account parameter:
raw-compile-svm.ts

Throws

A compile error, a resolve error or an invalid option. See Compile errors.

Closure entries and bound arguments

With entryKind: "closure", the entry is one arrow or function expression, exactly as Function.prototype.toString prints it. Its parameters and return type are main’s, and a concise body is main’s return. Diagnostics point into the closure text. args then compiles main’s scalar arguments in as known values, so the program takes none at run time:
closure-args.ts
The bound program decided require(amount >= minimum) while compiling. Its entryParams is empty, and entrySignature still lists both parameters. The closure is SauceScript text: the compiler does not run it as JavaScript or capture host variables. Each args value is one word: a bool, or a non-negative integer below 2^256 as a bigint or a decimal or 0x string. The raw option takes no bytes, arrays or records, and refuses -10n (not a valid integer literal); pass a negative Int256 as its two’s-complement word, (1n << 256n) - 10n. compileSauceProgram’s args takes -10n for an Int256 parameter.

Nested programs

A program can compile a closure as a program of its own with program(closure, ...args). Each one appears in programs, with the names it captures from the program around it:
programs-report.ts
path lists the programs a nested program sits in, outermost first, and captures lists the words its args carry, in order. Inside the program, program() returns { code, args }; the captured values and the closure’s parameters are read-only.

The SDK’s modules

resolveSdkModule and resolveSdkPackage serve, from memory, the files compileSauceProgram serves without being asked: the @sauce/token and @sauce/router libraries, ./artifacts/IERC20.json, ./artifacts/ISauceRouter.json and every ./protocols/<slug>/<Export>.json. Fall back to them from your resolver:
raw-compile-sdk-modules.ts
The package also ships the libraries’ files under sdk/dist/std/token/ and sdk/dist/std/router/ (one .evm.js and one .svm.js arm each, and the ABIs they bind) for a toolchain that resolves packages from disk. The compiler picks the arm by target.

ready

Initializes the compiler’s WebAssembly where the environment needs it. In Node it resolves at once and ignores source; in a browser, every compile throws until it has resolved.

Import

Usage

ready.ts

Signature

Parameters

Returns

A promise that resolves once the compiler can run. Calling ready() again is harmless, and a failed attempt is not remembered, so a later call tries again. The overview shows a browser entry that passes a URL.

Compile errors

All three functions throw on a compile error. A located source error, such as the undeclared variable below, has three headlines with ANSI bold codes; the source line and caret are plain. An error from a failed import has more headlines, so do not rely on a fixed count. The codes are always emitted, so strip them (stripVTControlCharacters from node:util) before matching or logging the text. Its diagnostics array places each source error. compileSauceProgram and compileSauceRoute can also throw a parse SyntaxError with no ANSI codes and no diagnostics. The raw compile reports a parse error through the compiler’s error report instead.
compile-error.ts
Each diagnostic is { path, message, start, end, secondary?, code? }:
  • path: the module as resolve was asked for it. An error in an imported module names the import.
  • start, end: { offset, line, column }. Lines and columns start at 1, and counts are UTF-16 code units, so source.slice(start.offset, end.offset) is the span.
  • secondary: a second location with its own note, where there is one.
  • code: the error’s stable name, such as UnknownIdentifier, UnknownFunction or TypeMismatch. Match on it rather than on message. A parse or subset error has none.
An error with no place in the source, such as an invalid option or a resolver failure, has an empty diagnostics array. A message your resolver throws is kept. compileSauceProgram and compileSauceRoute compile the rewritten source as main.js, so their diagnostics name main.js. The /compiler subpath does not export a type for the error; narrow it as the example does.

Next steps