Skip to main content
These five examples build from a payment to a program that compares swap quotes and supplies the output to a lending protocol. Read them in order to learn the language, or use the Sauce SDK quickstarts for complete task-specific recipes.

Prerequisites

Read the introduction for the roles of a program, Pot and cook. To run the examples, complete the SDK quickstart. The examples use SauceScript globals such as USDC and pot; only library functions need imports. The programs target Base and Ethereum. The recorded simulations used a local fork of Base at block 53122981 with the documented release’s contracts and an owner without a Pot. The simulation created a Pot before running each cook. Output is abridged, addresses are shortened and results can differ at another block. These results are simulation evidence, not a record of live transactions.

A payment to several recipients

payout.sauce.ts
  • recipients is an array parameter. The CLI takes it as JSON and encodes it after the bytecode with amount.
  • amount * recipients.length is checked arithmetic: an overflow reverts the transaction instead of wrapping.
  • require runs before any transfer. If the Pot holds too little, nothing is paid.
  • for...of iterates over an array. Each USDC.transfer is a separate token call from the Pot.
This program does not compile for Solana: a token transfer there needs the recipient’s token account listed in the transaction, and to is known only inside the loop. EVM and Solana shows how a Solana program takes such accounts.

Reading a pool

A program can read a protocol and return a value. Running it with sauce simulate gives you the result without sending a transaction.
quote.sauce.ts
  • UniswapV3.QuoterV2 is the chain’s deployment of Uniswap’s QuoterV2. The registry supplies its address and ABI, so the call is typed: its struct parameter is written as a record, and a misspelled or missing field fails the compile.
  • quoteExactInputSingle returns four values. const [amountOut] = … keeps the first.
  • A Uniswap V3 fee tier is in millionths: 500 is 0.05%, 3000 is 0.3%.
  • main declares Uint256 as its return type, so the cook returns one 32-byte word and the CLI decodes it.
With --args 10000000000000000, 0.01 WETH is quoted at 23.304536 USDC.

Comparing two pools

best-tier.sauce.ts
  • quote is a helper: a top-level function with annotated parameters and return type. It exists because the program quotes twice.
  • interface Quote declares a record type. main returns one, and the cook returns its fields as one word each.
  • Both quotes read the pools as they are when the transaction executes, not when it was built.

Swapping on the better pool

swap-best.sauce.ts
  • @sauce/router is the SDK’s swap library. uniswapV3 takes the pool, the input and output tokens, the input amount, a price limit, the minimum output and the recipient, and returns what the recipient received.
  • minOut is the minimum accepted output, supplied as a main parameter. If the swap returns less, uniswapV3 reverts; because this program does not catch the failure, the whole transaction reverts.
  • The price limit 0 sets none, so minOut is the only bound on the price. Security considerations explains when to set one.
  • UniswapV3.Factory.getPool reads the pool’s address for the chosen fee tier.
  • A Uniswap V3 pool pays out first and then calls its caller back to be paid. The Pot’s Router answers that callback and pays the pool from the Pot. @sauce/router lists which venues work this way.
In this simulation, the swap delivered 23304536, matching the 0.05% pool’s quote. The program obtained the quote and performed the swap within the same transaction; minOut remains the explicit lower bound on the output.

Supplying the output to Aave

swap-and-supply.sauce.ts
  • The swap’s recipient is pot, the Pot, so the USDC stays in the Pot for the next call.
  • received is what the swap returned, the amount the pool reports it paid. The program approves and supplies exactly that amount, so no allowance is left standing after the supply.
  • USDC.approve resets a non-zero allowance to zero before setting the new one, as OpenZeppelin’s forceApprove does.
  • AaveV3.Pool.supply(asset, amount, onBehalfOf, referralCode) is Aave’s own function, called by name. Aave mints the aTokens to beneficiary. With pot instead, they would stay in the Pot, and only a later cook could move them.
  • The require fails early with a readable reason. uniswapV3 enforces the same floor on the amount the pool reports it paid.
The “Approvals” line is the approval the program set before the supply; Aave’s supply then pulled the full 23.304536 USDC. With minOut at 30 USDC, above both quotes, the same simulation reverts and nothing moves:

What these programs used

Next steps