Developers
TypeScript SDK
Decoders, address derivation, instruction builders, the exact pool math and the built-in hooks, for wallets, routers and bots.
The SDK is the @socket/backend package, imported from @socket/backend/sdk. It is not on npm yet; it comes with the Socket source. It depends on @solana/web3.js 1.x and @solana/spl-token. All amounts, liquidity and prices are bigint.
Two layers#
- Raw builders and decoders need no network. They encode instructions exactly as the program expects and check their arguments, so a wallet can build a transaction offline.
SocketClientwraps an RPC connection. It validates the deployment, resolves pools with their hook accounts, checks token accounts, and returns unsigned transactions.
Set up a client#
import { Connection } from "@solana/web3.js";
import { SocketClient, DEFAULT_PROGRAM_ID, BUILTIN_HOOK_PROGRAM_ID } from "@socket/backend/sdk";
const rpc = new Connection(process.env.SOLANA_RPC_URL!, "finalized");
const socket = new SocketClient(rpc, DEFAULT_PROGRAM_ID, [BUILTIN_HOOK_PROGRAM_ID], process.env.SOLANA_GENESIS_HASH);
// Checks the cluster's genesis hash and that the Socket program is deployed.
await socket.validateDeployment();The third argument is the hook allowlist. resolvePool refuses pools whose hook isn't on it.
Swap#
import { ComputeBudgetProgram } from "@solana/web3.js";
import { swapInstruction } from "@socket/backend/sdk";
const accounts = await socket.operationAccounts(pool, wallet, userA, userB, undefined, { createTokenAccounts: true });
// Solana's default 200,000 units is not enough for a swap that crosses many ticks or calls a hook.
const budget = ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 });
const ix = swapInstruction(accounts, {
amount: 1_000_000_000n, // 1 token A with 9 decimals
limit: 0n, // no price limit beyond the domain end
aToB: true,
exactIn: true,
threshold: minOut, // from your quote, minus slippage
maxTotalInput: 1_000_000_000n,
});
const unsigned = await socket.unsignedTransaction(wallet, [budget, ...accounts.setup, ix]);
// unsigned.transaction is base64: inspect it, sign it, send it.operationAccounts resolves the pool and its hook extras and validates both token accounts. With createTokenAccounts, it returns setup instructions that create missing associated token accounts.
Quote locally#
import { swap, dynamicFeeAt, BUILTIN_HOOK_PROGRAM_ID, MIN_SQRT_PRICE, MAX_SQRT_PRICE } from "@socket/backend/sdk";
const { pool } = await socket.resolvePool(address);
let fee = pool.baseFeePpm;
// only the built-in hook's fee can be predicted from state; resolveHook reads built-in hooks only
if (pool.hookProgram.equals(BUILTIN_HOOK_PROGRAM_ID) && pool.permissions & 1 && pool.permissions & 16) {
const { state } = await socket.resolveHook(address);
if (state.config.kind === "dynamic-fee") fee = dynamicFeeAt(state, pool.baseFeePpm, pool.maxFeePpm, Math.floor(Date.now() / 1000));
}
// the math takes an explicit limit; only swapInstruction turns 0 into the domain end
const limit = aToB ? MIN_SQRT_PRICE : MAX_SQRT_PRICE;
const result = swap(pool, pool.ticks, amount, limit, aToB, true, fee);swap is a line-for-line bigint port of the Rust crate: the same rounding, tick crossings and errors (MathError codes like INSUFFICIENT_LIQUIDITY, ZERO_OUTPUT, INVALID_LIMIT).
What's exported#
| Area | Exports |
|---|---|
| Addresses | DEFAULT_PROGRAM_ID, BUILTIN_HOOK_PROGRAM_ID, derivePool, deriveVaults, derivePosition, deriveExtraAccountMetaList, deriveHookAuthority, deriveHookState |
| Decoders | decodePool, decodePosition, decodeExtraAccountMetaList, decodeHookState, decodeTwapReply |
| Instructions | initializeInstruction, openPositionInstruction, addLiquidityInstruction, removeLiquidityInstruction, collectFeesInstruction, swapInstruction, collectHookFeesInstruction, cancelRangeOrderInstruction, observeTwapInstruction |
| Built-in hooks | builtinHookInitialization, builtinHookExtra, dynamicFeeAt, rangeOrderAfterSwap |
| Math | tickToSqrtPrice, sqrtPriceToTick, amountDeltaA, amountDeltaB, positionAmounts, liquidityForAmount, feeInside, swap, constants MIN_TICK, MAX_TICK, MIN_SQRT_PRICE, MAX_SQRT_PRICE, Q64 |
| Client | SocketClient: validateDeployment, resolvePool, resolvePosition, resolveHook, operationAccounts, ownerPositions, mintDecimals, prepareInitialize, unsignedTransaction |
Errors#
SDK functions throw SocketError with a stable code (for example POOL_PARAMETERS, HOOK_PERMISSIONS, EXTRA_ALIAS, ACCOUNT_NOT_FOUND) and a message. Math errors are MathError, a subclass. Program errors returned by a failed transaction are listed in Errors.