Initializing a new pool
Hadron.initialize
Builds all the instructions needed to create a new on-chain pool: account allocation + initialization. Returns the instructions and the derived pool address.
The allocate instruction(s) must be confirmed before sending the initialize instruction (they can be in separate transactions, or together if they fit).
import { Hadron, Q32_ONE } from "@hadron-so/sdk";
const { instructions, poolAddress, seed } = Hadron.initialize(payer, {
mintX,
mintY,
authority: payer,
initialMidpriceQ32: Q32_ONE, // midprice = 1.0
});
// Send the instructions (group into transactions as needed)
// ...
// After confirmation, load the pool
const pool = await Hadron.load(connection, poolAddress);
| Param | Type | Description |
|---|
payer | PublicKey | Transaction fee payer and account funder |
params.seed? | bigint | Pool seed. Auto-generated if omitted. Allows multiple pools per token pair. |
params.mintX | PublicKey | Base token mint |
params.mintY | PublicKey | Quote token mint |
params.authority | PublicKey | Pool authority (manages curves, oracle, state) |
params.initialMidpriceQ32 | bigint | Starting midprice in Q32 fixed-point format |
params.oracleMode? | OracleMode | Authority (default) or Relative (vault ratio) |
params.tokenProgramX? | PublicKey | Token program for X (default: SPL Token) |
params.tokenProgramY? | PublicKey | Token program for Y (default: SPL Token) |
params.maxPrefabSlots? | number | Max curve prefab slots (default: 10) |
params.maxCurvePoints? | number | Max points per curve (default: 16) |
Returns { instructions: TransactionInstruction[], poolAddress: PublicKey, seed: bigint }
With default parameters the CurvePrefabs account is ~15 KB, so two allocate instructions are returned (Solana’s single-instruction realloc limit is 10 KB). Send the allocates first, then the initialize.
Loading an existing pool
Hadron.load
Load a pool from its on-chain address. Fetches config, oracle, curve metadata, and prefab data in parallel.
const pool = await Hadron.load(connection, poolAddress);
| Param | Type | Description |
|---|
connection | Connection | Solana RPC connection |
poolAddress | PublicKey | The pool’s on-chain address |
Returns Promise<Hadron>
Hadron.loadFromSeed
Derives the pool address from (seed, mintX, mintY) then calls create.
const pool = await Hadron.loadFromSeed(connection, seed, mintX, mintY);
| Param | Type | Description |
|---|
connection | Connection | Solana RPC connection |
seed | bigint | Pool seed |
mintX | PublicKey | Base token mint |
mintY | PublicKey | Quote token mint |
Returns Promise<Hadron>
Reading pool state
refetchStates
Re-fetches all on-chain accounts (config, oracle, curve metadata, prefabs) in parallel and updates the instance in-place.
await pool.refetchStates();
Returns Promise<void>
getMidprice
Current midprice decoded from the on-chain Q32 oracle value.
const mid = pool.getMidprice(); // e.g. 1.0023
Returns number
getSpreadFactor
Current spread factor decoded from the on-chain Q32 oracle value. A factor of 0.9995 means 5 bps of spread.
const factor = pool.getSpreadFactor(); // e.g. 0.9995
const bps = pool.getSpreadBps(); // e.g. 5
Returns number
getActiveCurveSlots
Returns the slot index for each active curve.
const slots = pool.getActiveCurveSlots();
// { priceBid: 0, priceAsk: 0, riskBid: 0, riskAsk: 0 }
Returns { priceBid: number, priceAsk: number, riskBid: number, riskAsk: number }
getActiveCurves
Decodes and returns all four active curves from prefab data.
const curves = pool.getActiveCurves();
// curves.priceBid.points, curves.priceAsk.points, etc.
Returns { priceBid: CurveSide, priceAsk: CurveSide, riskBid: CurveSide, riskAsk: CurveSide }
Each CurveSide contains:
| Field | Type | Description |
|---|
numPoints | number | Number of curve points |
defaultInterpolation | Interpolation | Default interpolation mode |
xMode | CurveXMode | X-axis mode (Native or Alternate) |
riskMode | RiskMode | Virtual or Integrated |
points | CurvePoint[] | The curve point array |
getCurveSlot
Decode a specific curve slot by type and index.
const curve = pool.getCurveSlot(CurveType.PriceBid, 1);
| Param | Type | Description |
|---|
curveType | CurveType | One of PriceBid, PriceAsk, RiskBid, RiskAsk |
slot | number | Slot index |
Returns CurveSide
Building instructions
All methods below return a TransactionInstruction. They do not send a transaction — add the instruction to a Transaction or VersionedTransaction and submit it yourself.
swap
Build a swap instruction.
const ix = pool.swap(user, {
isX: true, // true = sell token X for Y, false = sell Y for X
amountIn: 1_000_000n,
minOut: 0n,
feeRecipient: feePk,
});
| Param | Type | Description |
|---|
user | PublicKey | The user’s wallet |
params.isX | boolean | Direction: true = X→Y, false = Y→X |
params.amountIn | bigint | Input amount in token atoms |
params.minOut | bigint | Minimum output (slippage protection) |
params.feeRecipient | PublicKey | Address to receive fees |
params.expiration? | number | Optional slot expiration |
deposit
Build a deposit instruction.
const ix = pool.deposit(user, {
amountX: 1_000_000n,
amountY: 2_000_000n,
});
| Param | Type | Description |
|---|
user | PublicKey | The user’s wallet |
params.amountX | bigint | Amount of token X to deposit (in atoms) |
params.amountY | bigint | Amount of token Y to deposit (in atoms) |
params.expiration? | number | Optional slot expiration |
withdraw
Build a withdraw instruction.
const ix = pool.withdraw(user, {
amountX: 500_000n,
amountY: 1_000_000n,
});
| Param | Type | Description |
|---|
user | PublicKey | The user’s wallet |
params.amountX | bigint | Amount of token X to withdraw (in atoms) |
params.amountY | bigint | Amount of token Y to withdraw (in atoms) |
params.expiration? | number | Optional slot expiration |
Curve management
setCurve
Write a price curve to a prefab slot.
const ix = pool.setCurve(authority, {
side: Side.Bid,
defaultInterpolation: Interpolation.Linear,
points: [
{ amountIn: 100_000n, priceFactor: 0.99 },
{ amountIn: 500_000n, priceFactor: 0.95 },
],
slot: 0,
});
| Param | Type | Description |
|---|
authority | PublicKey | Pool authority |
params.side | Side | Bid or Ask |
params.defaultInterpolation | Interpolation | Step, Linear, MarginalStep, Hyperbolic, Quadratic, Cubic |
params.points | SetCurvePointInput[] | Array of { amountIn, priceFactor, interpolation?, params? } |
params.slot? | number | Target prefab slot (default: 0) |
params.xMode? | CurveXMode | X-axis mode |
setRiskCurve
Write a risk curve using percent-of-vault x-axis.
| Param | Type | Description |
|---|
authority | PublicKey | Pool authority |
params.side | Side | Bid or Ask |
params.defaultInterpolation | Interpolation | Interpolation mode |
params.points | SetRiskCurvePointInput[] | { pctBase: 0.0–1.0, priceFactor, ... } |
params.slot? | number | Target prefab slot |
params.riskMode? | RiskMode | Virtual or Integrated |
setRiskCurveAbsolute
Write a risk curve using absolute token amounts on the x-axis.
| Param | Type | Description |
|---|
authority | PublicKey | Pool authority |
params.side | Side | Bid or Ask |
params.defaultInterpolation | Interpolation | Interpolation mode |
params.points | SetRiskCurveAbsolutePointInput[] | { vaultBalance, priceFactor, ... } |
params.slot? | number | Target prefab slot |
params.riskMode? | RiskMode | Virtual or Integrated |
switchPriceCurve / switchRiskCurve
Activate a previously written curve slot (hot path — no curve data uploaded).
pool.switchPriceCurve(authority, { side: Side.Bid, slot: 1 });
pool.switchRiskCurve(authority, { side: Side.Ask, slot: 2 });
| Param | Type | Description |
|---|
authority | PublicKey | Pool authority |
params.side | Side | Bid or Ask |
params.slot | number | Slot to activate |
submitCurveUpdates / applyCurveUpdates
Two-step batched curve editing. Submit a list of point edits, then apply them.
pool.submitCurveUpdates(authority, [
{ curveType: CurveType.PriceBid, opKind: CurveUpdateOpKind.Edit, pointIndex: 0, ... },
]);
pool.applyCurveUpdates(authority);
Oracle management
updateMidprice
pool.updateMidprice(authority, { midpriceQ32: newMidQ32 });
| Param | Type | Description |
|---|
params.midpriceQ32 | bigint | New midprice in Q32 format |
params.sequence? | bigint | Optional sequence number for ordering |
updateBaseSpread
pool.updateBaseSpread(authority, { spreadFactorQ32: newSpreadQ32 });
| Param | Type | Description |
|---|
params.spreadFactorQ32 | bigint | Spread discount factor in Q32 (e.g. toQ32(0.9995) = 5 bps) |
params.sequence? | bigint | Optional sequence number |
updateMidpriceAndBaseSpread
Atomic update of both values in a single instruction.
pool.updateMidpriceAndBaseSpread(authority, {
midpriceQ32: newMidQ32,
spreadFactorQ32: newSpreadQ32,
});
Admin
nominateAuthority / acceptAuthority
Two-step authority transfer.
pool.nominateAuthority(authority, { newAuthority: newPk, expirySlot: 300_000_000n });
// ... newAuthority signs:
pool.acceptAuthority(newPk);
setPoolState
pool.setPoolState(authority, { newState: PoolState.Paused });
States: Uninitialized, Initialized, Paused, WithdrawOnly
updateDeltaStaleness
pool.updateDeltaStaleness(authority, { deltaStaleness: 150 });
closePool
Closes the pool and reclaims rent. Requires authority and all vaults to be empty.
pool.closePool(authority);
Properties
These are available on any Hadron instance after creation:
| Property | Type | Description |
|---|
pool.poolAddress | PublicKey | The pool’s on-chain address |
pool.programId | PublicKey | Program ID |
pool.addresses | PoolAddresses | All derived PDA addresses for this pool |
pool.config | DecodedConfig | Decoded config account data |
pool.oracle | DecodedMidpriceOracle | Decoded oracle data |
pool.curveMeta | DecodedCurveMeta | Decoded curve metadata |