Skip to main content
@eco-incorp/sauce/verify validates an EVM settlement payload against the pinned settle program (SETTLE_WIRE: compiler 2.3.0, 356 bytes) and decodes its runtime argument tail. It depends on viem only, so it runs in browsers and edge runtimes without loading the compiler. This page covers sdk/dist/verify/decode.d.ts.
Generated from the type declarations shipped in @eco-incorp/sauce 0.99.4. Each entry shows the package authors’ JSDoc and declaration for this SDK version. For runtime compatibility and deployed addresses, see architecture and deployments.

decodeSettleProgram

Function · sdk/dist/verify/decode.d.ts Decode a settle payload back into (tokens, minOut, recipient). STRICT: rejects a non-canonical tokens pointer, a tail longer or shorter than the token count implies, an address word with dirty upper bytes, and a zero recipient - see §4 for why. Throws SettleDecodeError (carrying a stable .code) on any of the failures in SettleFailureCode. This is a STRUCTURAL decode: it proves the payload is 356 bytes || a canonical argument tail. It does NOT prove those 356 bytes are the settle program you audited - any 356-byte prefix passes. Use validateSettleProgram when that matters, which is nearly always.

validateSettleProgram

Function · sdk/dist/verify/decode.d.ts decodeSettleProgram plus the authenticity pin: the payload’s 356 program bytes must hash to SETTLE_WIRE.PROGRAM_HASH. Because the arguments no longer live inside the program, a match means the payload runs the audited recipes/settle.sauce.ts and nothing else - the whole question, not the structural half. Throws SettleDecodeError with code PROGRAM_HASH when the program is a different 356 bytes, and whatever decodeSettleProgram would throw otherwise. accepted overrides the pin. The dependency is a caret range and SETTLE_WIRE documents that a codegen change is answered by RE-PINNING - at which point every intent already on chain carries the OLD program, and a single hard-coded pin makes all of them unverifiable. Pass the pins you accept (the current one plus any historical ones) to keep those payloads readable across a re-pin. A PIN IS A HASH AND A LENGTH, which is why a bare hash is not enough. The payload is split into program and argument tail at a byte offset, before any hash is computed - so if a re-pin changes the program’s length (the likely outcome of a codegen change), splitting a historical payload at the NEW length yields a wrong program and a truncated tail, and it dies as ARGS_TRUNCATED without any hash ever being compared. Each entry may be { hash, bytes }; a bare Hex means the CURRENT SETTLE_WIRE.PROGRAM_BYTES and is only safe for a same-length re-pin. Candidates are tried in order and the first whose program hash matches wins. Defaults to the current pin.

encodeSettleProgram

Function · sdk/dist/verify/decode.d.ts §5 of the wire spec - the cheaper, EQUIVALENT alternative to scan-and-check: when the caller already knows the intended (tokens, minOut, recipient) (the normal case - they asked for the swap), encode them directly and memcmp/hash-compare the whole payload rather than decoding. Given §4 this produces the UNIQUE canonical encoding, so encodeSettleProgram(...) equals payload exactly when validateSettleProgram(payload) succeeds with those values - in one comparison, with no parser exposed to a hostile input at all. This is the recommended non-TypeScript (Solidity/Go/Python) implementation, where a payload is bytes and the comparison is a plain memcmp. THE EQUIVALENCE IS OVER BYTES, NOT OVER HEX SPELLINGS. validateSettleProgram accepts any spelling of the same bytes - uppercase, a 0X prefix, no prefix at all - while this returns canonical lowercase 0x. So validateSettleProgram(p.toUpperCase()) succeeds where encodeSettleProgram(...) === p.toUpperCase() is false. A string === is only equivalent once both sides are in canonical spelling; normalize first, or compare decoded bytes. programHex is supplied by the caller - pass the program you compiled yourself. There is deliberately no default: the bytes you compare against should be ones you derived, not ones shipped alongside the claim they support. SETTLE_WIRE.PROGRAM_HASH is what to check them against once you have them.

parseSettleProgram

Function · sdk/dist/verify/decode.d.ts Best-effort single left-to-right pass - never throws. This is the shared engine both decodeSettleProgram (throws on parse.fatal) and bestEffortDecode (keeps whatever DID parse even when a later stage failed) run on top of.

bestEffortDecode

Function · sdk/dist/verify/decode.d.ts Decode whenever the shape is well-formed enough to name a full (tokens, minOut, recipient) - even when a check that does not block reading (a trailing-slack tail, a dirty address word, a zero recipient) would make decodeSettleProgram throw - so a rejected payload’s decoded intent is still visible to a caller debugging the rejection. DECLINES wherever the report would not match execution - the whole point being that on a hostile payload, reporting nothing beats reporting a wrong answer confidently. Two cases:
  • a non-canonical tokens pointer: the engine follows it, this reads at the canonical offset, so the two name different TOKENS.
  • a dirty RECIPIENT word: recipient is masked here, but the engine does not mask that word (§4), so execution addresses a different 256-bit key than the masked answer would suggest.
A dirty TOKEN word is NOT declined: the engine masks a call target to 160 bits, so there the masked answer is exactly what executes, and reporting it is what shows the payload’s true meaning.

SettleDecodeError

Class · sdk/dist/verify/decode.d.ts

DecodedSettleProgram

Interface · sdk/dist/verify/decode.d.ts

ProgramPin

Interface · sdk/dist/verify/decode.d.ts An accepted program: its keccak256 AND the byte length the payload splits at. Both are needed - the split happens before any hash is computed, so a historical pin whose program was a different length cannot be matched by hash alone.

SettleFailureCode

Type · sdk/dist/verify/decode.d.ts Stable failure codes - safe to switch on. Every one is a REAL rejection this decoder makes. BREAKING vs the v1 grammar: eight codes are GONE, because the defects they named cannot occur on a fixed-width wire. NON_MINIMAL_PUSH, TRUNCATED_PUSH, TRUNCATED_MINOUT, TRUNCATED_RECIPIENT and OVERSIZE_ADDRESS all described a variable-length PUSH prologue that no longer exists; ARITY_MISMATCH and NOT_SETTLE_SHAPED described shape inference the whole-program hash now settles outright; BODY_LENGTH described a body slice that is no longer a separate region. Their uniqueness role is taken by §4’s canonicality rules and PROGRAM_HASH. Only EMPTY and ZERO_RECIPIENT carry over. A consumer with an exhaustive switch on the old union will compile and silently stop matching, which is why this ships as a breaking change.

SettleParse

Interface · sdk/dist/verify/decode.d.ts Internal parse result - used by both the throwing decodeSettleProgram and the non-throwing bestEffortDecode, which keeps partial state past a failure.

Address20

Type · sdk/dist/verify/decode.d.ts A 20-byte address rendered as lowercase 0x-hex - deliberately NOT viem’s Address branded type: callers that want an EIP-55 checksum should getAddress() it themselves.