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 minttake_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)}`);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.