Developers
TypeScript SDK
Addresses, account decoders, every instruction builder, the program's valuation and the targets' quotes, in one package. The app is built on it.
npm install @yoke/sdk @solana/web3.js@1.98.4Amounts are bigint in token base units: USDC has six decimals, wrapped SOL nine. Builders take the deployed program ID as their last argument; pass it everywhere. Decoded accounts are plain JSON with decimal strings. The SDK never holds or asks for a key.
Read an account
readCredit reads the pool, the credit account, the registry, the vault and all four token accounts from one finalized bank, and checks the chain's genesis hash first.
import { Connection, PublicKey } from "@solana/web3.js";
import { readCredit } from "@yoke/sdk";
const connection = new Connection(RPC_URL, "confirmed");
const account = await readCredit(connection, owner, GENESIS_HASH, PROGRAM_ID);
account.credit.debtUnits; // "18000000000"
account.custody; // [{ asset: 0, mint, address, amount }, … ]Value it like the program
readTargets reads both targets and the clock at one bank. valueCredit and health apply the program's weights, buffer and rounding.
import { health, readTargets, valueCredit } from "@yoke/sdk";
const targets = await readTargets(connection, config);
const value = valueCredit(targets, { usdc, wsol, ctoken, lp });
const h = health(value.collateral, debt);
h.ratioBps; // 12097n, so 1.20
h.meetsBuffer; // true: a move ending here passes
h.liquidatable; // falsevalue.counted breaks the collateral down by holding, and value.lpWsol is the SOL side of the LP, which is never counted.
Preview a move
projectSession walks steps through the targets' own math, in order, and returns the account and targets after each one. It throws a readable error when the account can't cover a step.
import { projectSession, valueCredit, health } from "@yoke/sdk";
const after = projectSession(targets, custody, [
{ action: 0, amount: 2_500_000000n }, // deposit 2,500 USDC into Save
{ action: 2, amount: lpTokens }, // add Orca liquidity
]);
const next = health(valueCredit(after.targets, after.custody).collateral, debt);Build and send a move
composeSession returns begin, the steps and end with the right indexes. buildV0 compiles a version 0 transaction with the lookup table and refuses anything over the packet limit.
import { adapterMetas, buildV0, composeSession, computeBudget, simulate } from "@yoke/sdk";
const prefix = computeBudget({ computeUnits: 1_000_000 });
const accounts = { actor: owner, owner, destinationUsdc, destinationWsol, external: adapterMetas(config) };
const steps = [
{ action: 0, amount: 2_500_000000n, limitA: minReceipts, limitB: 0n },
{ action: 2, amount: lpTokens, limitA: maxUsdc, limitB: maxSol },
] as const;
const ixs = composeSession(accounts, nonce, 0, [...steps], { withdrawUsdc: 0n }, prefix.length, PROGRAM_ID);
const tx = buildV0(owner, blockhash, [...prefix, ...ixs], tables);
const sim = await simulate(connection, tx);
if (sim.error) throw new Error(JSON.stringify(sim.error));Sign tx with the owner's wallet and send it. nonce is the account's stored nonce plus one.
Exports
| Area | Functions |
|---|---|
| Addresses | poolAddress, vaultAddress, creditAddress, custodyAddress, lenderAddress, registryAddress |
| Accounts | decodeYokeAccount, readPool, readCredit |
| Pool | deposit, withdraw, quotePool, quoteDeposit, quoteWithdraw |
| Credit | openCredit, addCollateral, borrow, repay, release |
| Moves | begin, adapter, end, composeSession, sessionMetas, adapterMetas |
| Transactions | computeBudget, buildV0, buildSessionV0, loadLookupTables, simulate |
| Valuation | readTargets, decodeTargets, valueCredit, health, saveCash, saveWorth |
| Target quotes | quoteSaveDeposit, quoteSaveRedeem, quoteLpDeposit, quoteLpWithdraw, lpForUsdc, projectSession, orcaSpotPrice |
| Tokens | associatedTokenAddress, createAssociatedTokenIdempotent, wrapSol, unwrapSol |
| Constants | USDC_MINT, WSOL_MINT, SAVE_PROGRAM, ORCA_PROGRAM, LENDING_WEIGHT_BPS, LP_WEIGHT_BPS, BUFFER_BPS, PREMIUM_BPS |