@sauce/token reads and moves tokens: ERC-20 on EVM chains, SPL Token and Token-2022 on Solana. The token methods (USDC.transfer(…), Token(token).approve(…), pot.USDC) compile to calls into it, so a token write has one implementation however it is spelled.
The CLI and routes.compileSauceProgram make these functions available without imports. Pass the token as the first argument. You can also import the functions explicitly:
token-functions.sauce.ts
token-import.sauce.ts
transferChecked is available only on Solana. On EVM, importing it reports “transferChecked is not exported by module …”; using it without an import reports “transferChecked is called but never declared”. See library target selection.
On EVM chains
Reads
The reads are typed ERC-20 calls. A call to an address with no code returns no data, so the read reverts.Writes
The writes have OpenZeppelinSafeERC20 semantics:
- Empty return data is success only from an address with code. A token that returns nothing, such as USDT, works. A write to an address with no code reverts, so a mistyped address cannot pass silently.
- A non-empty reply must contain at least 32 bytes, with the first word equal to 1. A
falsereturn, a shorter reply or a first word other than 1 fails the check. approveisforceApprove. It reads the Pot’s current allowance for the spender, and when that is not zero, sets it to zero before setting the new amount. USDT refuses to change one non-zero allowance to another, so an approve works only from zero.- Writes return nothing. A write either succeeds or raises a failure. An unhandled failure reverts the cook; EVM programs can use the documented catch boundaries to handle one.
transferFromspends an allowance.frommust have approved the Pot for at leastamount.
IERC20.at(token).transfer(…) binding that a program writes itself, which decodes the declared bool: it reverts on USDT and accepts false. See Contracts and ABIs.
Signatures: permit and permitTransferFrom
permit sets an allowance on the holder’s signature and moves nothing; a later transferFrom pulls. permitTransferFrom pulls into the Pot in one step:
permitsubmits an EIP-2612permit(owner, spender, value, deadline, v, r, s)and then requires the token’s nonce forownerto have moved by exactly one. A token with nopermitbut a permissive fallback, such as WETH9, would otherwise pass for one that granted the allowance. AtransferFromthen spends the allowance. The token must havenonces(address), or the nonce read reverts.permitTransferFromcalls Permit2’s signature transfer, movingamountfromownerto the Pot onowner’s one-time signature. Permit2 spendsnonce, rejects an expireddeadline, and moves the tokens with the same empty-or-truecheck.
pull-permit2.sauce.ts
sauce run --fund signs a Permit2 or EIP-2612 permit with your wallet and adds these pulls to the program. See Funding.
On Solana
The Solana implementation supports both SPL Token and Token-2022. Its functions take the accounts they read or move through, because a Solana instruction lists every account it touches:Reads
- A token account must be owned by SPL Token, or by Token-2022 with the base account layout or an account-type byte of 2. A mint, a multisig or any other account is refused with
not a token account, and an account of another mint withwrong mint. totalSupplyanddecimalstake the mint as anAccount, not anAddress. The account must be an initialized mint of either program, or the read fails withnot a mintoruninitialized mint.ownerOfreturns the holder recorded in the token account, not the authority a write is signed by. SPL accepts the account’s delegate as the authority too, so a program that measures its own balance requiresownerOf(token, account)to equal the authority first.allowancereads the account’s single delegate. It returns the delegated amount when the account has a delegate and the delegate isspender, and 0 otherwise. A revoked delegate reads as 0.
Writes
transfer,transferFromandapprovecall SPL Token’s plain instructions. They requiretokenProgramto be SPL Token (not the token program),sourceto be an SPL Token account (not a token account) oftoken(wrong mint), andamountto fit 64 bits (amount over u64). A Token-2022 callee or account is refused.transferFromistransfer: SPL Token has one transfer instruction, and the authority you attach decides whether the owner or a delegate moves the funds.transferCheckedandapproveCheckedcarry the mint and its decimals. They require the callee to be SPL Token or Token-2022, the source, destination (for a transfer) and mint to be owned by that program,mintto be the named token, anddecimalsto be the mint’s own (wrong decimals).- A Token-2022 mint whose transfer hook names a program is refused with
transfer hook, before anything moves. The hook’s extra accounts cannot be carried in a fixed account list. A hook extension that names no program is no hook. An approval runs no hook, soapproveCheckeddoes not check for one. - The other Token-2022 extensions are the token program’s to apply. A transfer fee is withheld from what the destination receives, so measure the balance that arrived. A paused mint or a frozen account refuses the transfer with the token program’s own error, and amounts are always raw base units.
approvesets one delegate. SPL Token tracks a single delegate per account, so a second approve replaces the first, where an ERC-20 keeps an allowance per spender.- Amounts are 64-bit. An approval of
2^256 - 1, which an ERC-20 accepts, reverts withamount over u64.
The token methods choose the write
The token methods pick the write by the mint’s token program. An SPL Token mint (USDC, USDT, WSOL) moves with the plain transfer. A Token-2022 mint (PYUSD and the tokenized stocks) moves with transferChecked, using the registry’s decimals. Compiling adds each account the call moves through to main and derives it:
pay-pyusd.solana.sauce.ts
Account parameters of main:
checked.solana.sauce.ts
Next steps
- @sauce libraries: importing, and the EVM and Solana implementations.
- @sauce/router: swaps at each venue, built on these writes.
- Names: token symbols,
pot.<TOKEN>and the token methods. - EVM and Solana: accounts, token programs and size limits on Solana.
tokennamespace: the TypeScript API that emits these calls for a host program.
