Developers
SDK
Encode, sign and verify orders; read chain state; build instructions.
@chord/sdk is the TypeScript package the app, the collector and the reference solver all use. Amounts are SPL base units: bigint inside, canonical decimal strings at JSON boundaries. Nothing financial is ever a float.
npm install @chord/sdk @solana/web3.js#Orders
import { encodeIntent, intentHash, signIntent, verifyIntent, type IntentWire } from "@chord/sdk";
const intent: IntentWire = {
batch: batchAddress,
owner: wallet.toBase58(),
source: sourceTokenAccount,
destination: destinationTokenAccount,
sellMint: mintB,
buyMint: mintA,
sellAmount: "500000000",
minBuyAmount: "3496503496",
nonce: "1759312245123456",
expirySlot: deadlineSlot,
allowPartial: false,
};
const domain = { programId, config, chainDomain }; // chainDomain: 32 bytes from /config
const envelope = signIntent(intent, domain, secretKey); // { intent, signature }
verifyIntent(envelope, domain); // true| Function | Returns |
|---|---|
encodeIntent(intent, domain) | The 336-byte canonical preimage |
intentHash(intent, domain) | Hex SHA-256 of the preimage: the order’s id |
signIntent(intent, domain, secretKey) | { intent, signature }, ready for POST /intents |
verifyIntent(envelope, domain) | Whether the envelope is canonical and the signature valid |
In a browser, sign the digest with the wallet instead of a secret key: wallet.signMessage(Buffer.from(intentHash(intent, domain), "hex")), then base64 the 64-byte result.
#Math
import { fillOutput } from "@chord/sdk";
// what an order receives for `sell` at a committed price
const out = fillOutput(intent, sell, mintA, { numerator: 711n, denominator: 5000n });fillOutput is the exact rounding the program uses. Use it to show users what a price means before they sign.
#Solving
import { referenceSolve, validateSolution } from "@chord/sdk";
const solution = referenceSolve({ mintA, mintB, orders, reserveA, reserveB, referencePrice });
if (solution) {
const check = validateSolution(input, solution); // throws on any inconsistency
console.log(check.netA, check.netB); // inventory you'll end up long or short
}| Function | Purpose |
|---|---|
referenceSolve(input) | The reference solver’s policy: limit and reference prices, exhaustive full fills up to 18 orders, bounded partials. null if nothing fills. |
validateSolution(input, solution) | Every check the collector makes, plus the net inventory change |
#Chain
ChordClient reads finalized Chord accounts, checks their owner, discriminator, length and PDA, and builds every instruction the program has.
import { Connection } from "@solana/web3.js";
import { ChordClient } from "@chord/sdk";
const client = new ChordClient(new Connection(rpcUrl, "finalized"));
client.configPda; // the config address
client.settlementPda; // the delegate an allowance must name
const cancel = client.cancelNonceInstruction(owner, nonce);It also builds solver registration, top-up and withdrawal, batch creation, commit, fill, finalize, timeout, expiry, refund claims, nonce cancellation and floor advancement, and SPL approve and revoke.
#Staking and governance
import { ChordClient, ChordGovernance, governanceAddress } from "@chord/sdk";
const client = new ChordClient(connection);
const pool = await client.fetchStakePool();
const stake = client.stakeInstruction({ owner, pool, source: chordAccount, amount: 1_000_000_000_000n });
const unstake = client.unstakeInstruction(owner, 1_000_000_000_000n); // starts the 7-day cooldown
const withdraw = client.withdrawStakeInstruction({ owner, pool, destination: chordAccount });
const governance = governanceAddress(pool.realm, client.configPda);
const gov = new ChordGovernance(client, pool.realm, governance, pool.mint);
const vote = await gov.voteInstructions({ proposal, proposalOwner, voter: owner, payer: owner, approve: true });| Function | Purpose |
|---|---|
fetchStakePool(), fetchStake(owner), fetchMarket(mintA, mintB) | Finalized pool, stake and market state |
votingPower(stake, openedSlot?) | The weight a vote counts: active stake less deposits made once the proposal opened |
gov.joinInstructions(owner, payer) | The voter’s record in the realm, once per wallet |
gov.proposeInstructions(...), gov.insertInstructions(...), gov.signOffInstructions(...) | Open a proposal, attach what it executes, and start the vote |
gov.voteInstructions(...), gov.finalizeInstructions(...), gov.executeInstructions(...) | Vote, close the vote, and run a passed proposal after its hold-up |
Proposals and votes start with Chord’s voter weight update, so each transaction carries its own weight.
#Raydium inventory adapter
readRaydiumPool, buildRaydiumSwap and executeRaydiumSwap read a pinned Raydium CPMM pool from finalized state, quote it with its fees, and build one direct swap from a solver’s own token accounts, with slippage bounded to 10%. Settlement never calls it: use it to rebalance inventory between batches.