chordDocs

Protocol

Signed orders

The exact bytes you sign, and what binds them to one batch and chain.

An order is an intent: a fixed-layout message the owner signs with their wallet’s Ed25519 key. The same bytes are built by the app, the SDK and the program, and all three must agree to the byte.

#The preimage

The canonical preimage is 336 bytes, in this order:

BytesFieldEncoding
15Domain tagASCII CHORD_INTENT_V1
32ProgramChord’s program ID
32Chain domainSHA-256 of the cluster’s genesis hash string, fixed in the config
32ConfigThe config PDA
32BatchThe batch account
32OwnerThe signing wallet
32SourceOwner’s token account for the sell mint
32DestinationOwner’s token account for the buy mint
32Sell mint
32Buy mint
8Sell amountu64, little-endian
8Minimum buy amountu64, little-endian
8Nonceu64, little-endian
8Expiry slotu64, little-endian
1Allow partial0 or 1

#The digest

The wallet signs SHA-256(preimage), 32 bytes, not the preimage itself. This keeps the on-chain verification small while still committing to every field above.

TypeScript
import { encodeIntent, intentHash, signIntent } from "@chord/sdk";

const bytes = encodeIntent(intent, domain); // 336 bytes
const digest = intentHash(intent, domain);  // hex SHA-256 of those bytes
const envelope = signIntent(intent, domain, secretKey); // { intent, signature }

Browser wallets sign the digest with signMessage. The signature is 64 bytes, sent to the collector as base64.

#What binds a signature

  • Program, config and chain domain stop a signature from being used on another deployment or another cluster. The app checks that its RPC’s genesis hash produces the collector’s chain domain before it asks you to sign.
  • Batch stops it from being used in any other batch.
  • Owner, source and destination fix where tokens come from and go to.
  • Nonce makes every order unique per owner. The program writes a permanent receipt for each nonce it fills or cancels, so a nonce can’t be used twice.
  • Expiry slot must cover the batch’s settlement deadline. The program refuses fills after it.

#On-chain verification

settle_fill requires the instruction just before it to be a native Ed25519 verification with exactly one signature, laid out self-contained: public key at offset 16, signature at 48, message at 112, a 32-byte message, and all three instruction indices 0xFFFF. The program then checks that the public key is the order’s owner and the message is the digest it computes itself. The Ed25519 program checks the signature; Chord checks what was signed.