InviaInvia
App
SDK/Filling offers

Filling offers

Filling means delivering your side of the trade and atomically receiving the maker's side. The on-chain take_offer instruction enforces every check; the SDK only assembles the right accounts and arguments.

Pick a target

const { offers } = await invia.api.getOffers({ status: "open", limit: 50 });
const target = offers[0]!;

You can also fetch a specific offer by PDA: invia.api.getOffer(pda).

Decide a fill amount

import { fmtTokenAmount, totalFromPrice } from "@invia-app/sdk";

const remaining = BigInt(target.remainingSize);
const minFill = BigInt(target.minFill);

const fillAmount = remaining < minFill * 2n ? remaining : minFill;

const totalPay = totalFromPrice(
  fillAmount,
  BigInt(target.pricePerToken),
  target.priceScale,
);

console.log("paying", fmtTokenAmount(totalPay, 9), "wSOL"); // payment decimals depend on the mint

take_offer accepts any fillAmount between minFill and remainingSize, plus the special case where fillAmount == remainingSize (the final dust fill is always allowed).

Submit the take

import { PublicKey } from "@solana/web3.js";

const { signature } = await invia.program.takeOffer(wallet, {
  offer: new PublicKey(target.pda),
  maker: new PublicKey(target.maker),
  tokenMint: new PublicKey(target.tokenMint),
  paymentMint: new PublicKey(target.paymentMint),
  fillAmount,
});

Settlement is atomic. Either both legs succeed or the entire transaction reverts.

Pre-flight simulation

import { Connection, Transaction } from "@solana/web3.js";

const built = invia.program.buildTakeOfferIx({
  taker: new PublicKey(wallet.address),
  offer: new PublicKey(target.pda),
  maker: new PublicKey(target.maker),
  tokenMint: new PublicKey(target.tokenMint),
  paymentMint: new PublicKey(target.paymentMint),
  fillAmount,
});

const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
const tx = new Transaction({
  feePayer: new PublicKey(wallet.address),
  blockhash,
  lastValidBlockHeight,
}).add(built.ix);
const sim = await connection.simulateTransaction(tx);
if (sim.value.err) throw new Error(`Simulation failed: ${JSON.stringify(sim.value.err)}`);
Bring your own RPC

The SDK reads from chain through the Connection you pass to InviaClient. For production traffic use a dedicated RPC (Helius, Triton, Quicknode) rather than the public devnet endpoint.

Reading the trade preview

import { feeFromTotal, netAfterFee } from "@invia-app/sdk";

const totalPay = totalFromPrice(fillAmount, BigInt(target.pricePerToken), target.priceScale);
const fee = feeFromTotal(totalPay);
const net = netAfterFee(totalPay);

For a sell-side offer, the taker pays totalPay and receives fillAmount of the token. The maker receives net (= totalPay - fee) and the protocol treasury receives fee. For a buy-side offer the legs are swapped.