Skip to main content
Kimia does not publish an npm SDK. Instead, each program’s Anchor IDL is run through Codama and the result is committed to frontend/app/generated/<program>/. If you want to use these clients from another project, copy the folder — the only runtime dependency is @solana/kit. Every generated client has the same shape.

Client layout

app/generated/<program>/
├── accounts/
│   ├── <AccountName>.ts       # decoder, fetch*, size, discriminator
│   └── index.ts
├── instructions/
│   ├── <instructionName>.ts   # builder → IInstruction
│   └── index.ts
├── pdas/
│   ├── find<AccountName>Pda.ts
│   └── index.ts
├── programs/
│   └── <programName>.ts       # programId constant
├── errors/
│   └── index.ts               # typed error enum
├── types/                     # struct + enum codecs used by accounts
└── index.ts

Fetching an account

import { fetchMarket } from '@/app/generated/perp/accounts';

const market = await fetchMarket(rpc, marketPda);
console.log(market.data.totalLongBase);   // bigint
Every fetch returns a { exists, address, data, executable, lamports, ... } shape. fetchMaybeMarket is the non-throwing variant.

Resolving PDAs

import { findMarketPda } from '@/app/generated/perp/pdas';

const [marketPda, bump] = await findMarketPda({ marketIndex: 0 });
The helper knows the seeds from the IDL and does the derivation for you.

Building an instruction

import { getPlaceOrderInstruction } from '@/app/generated/perp/instructions';

const ix = getPlaceOrderInstruction({
  signer: walletSigner,
  userAccount: userAccountPda,
  market: marketPda,
  oracle: priceUpdateAccount,
  orderbook: orderbookPda,
  collateralVault: market.data.collateralVault,
  feeVault: market.data.feeVault,
  params: {
    price: 0n,
    baseAmount: 1_000_000_000n,
    direction: 0,               // 0 = Long, 1 = Short
    postOnly: false,
    isMarket: true,
    maxSlippageBps: 100,
  },
});
Each builder takes TransactionSigner, Address, and primitive types. The return is an IInstruction that fits directly into @solana/kit’s appendTransactionMessageInstruction.

Decoding events

Only kimia-perp and intent-router emit Anchor #[event] structs today — see the events reference. For those programs, Codama generates decoders under types/:
import { getOrderFilledDecoder } from '@/app/generated/perp/types';

function parseEvent(logBase64: string) {
  const bytes = Buffer.from(logBase64, 'base64');
  // Events are prefixed with an 8-byte discriminator
  return getOrderFilledDecoder().decode(bytes.slice(8));
}
The other programs (delta-vault, split-engine, yield-amm, kusd-mint) log via msg! rather than emitting events. To observe them, read tx.meta.logMessages after confirmation.

Sending a transaction

The repo’s frontend/app/lib/send-transaction.ts is the reference helper:
import { sendTransaction } from '@/app/lib/send-transaction';

const sig = await sendTransaction({
  rpc, rpcSubscriptions, wallet,
  instructions: [...postIxs, placeOrderIx],
  commitment: 'confirmed',
});
It handles:
  • Recent blockhash fetching
  • Wallet-standard signing via frontend/app/lib/wallet
  • preflight simulation + surfacing program logs
  • Typed error parsing via frontend/app/lib/errors.ts

Regenerating after a program change

cd frontend
npm run codama:all
Pin one program to regenerate only its client:
npm run codama:perp
npm run codama:delta
npm run codama:split
npm run codama:amm
npm run codama:intent
npm run codama:kusd
Every regeneration overwrites app/generated/<program>/. Never hand-edit files inside that directory.