@usefillr/sdk gives you typed instruction builders, PDA derivation, and account decoders. ~120 LOC of hand-rolled Borsh, @solana/web3.js as the only peer dep.

Install

bash
pnpm add @usefillr/sdk @solana/web3.js

PDA derivation

typescript
import { findCommitmentPda, findVaultAuthorityPda } from "@usefillr/sdk"; const [commitment] = findCommitmentPda(owner, nonce); const [vaultAuthority] = findVaultAuthorityPda(commitment);

The vault token ATA is the standard getAssociatedTokenAddressSync(paymentMint, vaultAuthority, true, TOKEN_PROGRAM_ID). The SDK ships a local findAssociatedTokenAddress helper to avoid the @solana/spl-token dep.

Build create_commitment

typescript
import { buildCreateCommitmentIx, PRICE_SCALE, WSOL_MINT, } from "@usefillr/sdk"; const ix = buildCreateCommitmentIx({ owner: wallet.publicKey, args: { targetMint: new PublicKey("..."), paymentMint: WSOL_MINT, paymentAmount: 10_000_000n, // 0.01 SOL in lamports maxPrice: 1_000_000_000_000n, // u128, 1e18 scale minFill: 1_000_000_000n, // 1 token at 9 decimals keeperBounty: 1_000_000n, // 0.001 SOL trigger: { kind: "jupiterRoutable", minLiquidityUsd: 1000n }, expiryTs: BigInt(Math.floor(Date.now() / 1000) + 7 * 86400), nonce: BigInt(Date.now()), targetDecimals: 6, userJitoTipLamports: 0n, // Jito tip for pump.fun fills }, });

Build execute_commitment

Used by keepers. Wraps a Jupiter /swap-instructions response into a fillr ix.

typescript
import { buildExecuteCommitmentIx } from "@usefillr/sdk"; const swapIx = await fetchJupiterSwapInstructions(...); const ix = buildExecuteCommitmentIx({ keeper: keeperKp.publicKey, commitment: commitmentPda, owner: c.owner, paymentMint: c.paymentMint, targetMint: c.targetMint, jupiterSwap: { data: swapIx.data, accounts: swapIx.accounts, }, });

Build cancel / expire

typescript
import { buildCancelCommitmentIx, buildExpireCommitmentIx } from "@usefillr/sdk"; const cancelIx = buildCancelCommitmentIx({ signer: owner, owner, commitment: commitmentPda, paymentMint: c.paymentMint, }); // expire is permissionless — signer can be anyone past expiry_ts const expireIx = buildExpireCommitmentIx({ signer: keeper, owner, commitment, paymentMint });

Decode a Commitment account

typescript
import { decodeCommitment } from "@usefillr/sdk"; const info = await connection.getAccountInfo(commitmentPda); if (info) { const c = decodeCommitment(commitmentPda, info.data); console.log(c.status, c.maxPrice, c.trigger); }

Constants

typescript
import { FILLR_PROGRAM_ID, TREASURY, USDC_MINT, USDT_MINT, WSOL_MINT, JUPITER_PROGRAM_ID, JUPITER_EVENT_AUTHORITY, SHARED_ACCOUNTS_ROUTE_DISCRIMINATOR, PRICE_SCALE, // 10n ** 18n PROTOCOL_FEE_BPS, // 20 MIN_KEEPER_BOUNTY_LAMPORTS, MAX_KEEPER_BOUNTY_LAMPORTS, } from "@usefillr/sdk";
On mainnet vs. devnet: only FILLR_PROGRAM_ID and TREASURY differ between deployments. Everything else (Jupiter, payment mints, scales) is identical across clusters because the upstream programs are deployed at the same addresses.