/** * @name perps/adrena/adrena-builder-core * @description Shared types, helpers, and utilities for Adrena perps builders. * * This module contains the common infrastructure used by all builder modules: * types (PositionSide, AdrenaPool, TokenBalance, BalanceCheck, UnsignedTransactionResult), * IDL loading, and all helper functions. * * @module perps/adrena/adrena-builder-core */ import { PublicKey, TransactionInstruction, Connection } from '@solana/web3.js'; import { Program } from '@coral-xyz/anchor'; import BN from 'bn.js'; /** Side of a perp position. */ export type PositionSide = 'long' | 'short'; /** Pool identifier. */ export type AdrenaPool = 'main-pool' | 'commodities-pool'; /** * Token balance for a single token in the owner's wallet. * All amounts are in human-readable units (e.g. 1.5 USDC = 1.5). */ export interface TokenBalance { /** Token symbol (USDC, JITOSOL, WBTC, BONK, SOL). */ symbol: string; /** Mint address. */ mint: string; /** Human-readable balance (adjusted for decimals). */ balance: number; /** Raw bigint balance (lamports/atoms). */ balanceRaw: string; /** Token decimals. */ decimals: number; /** ATA address (empty string if SOL). */ ata: string; /** Whether the ATA exists on-chain. */ ataExists: boolean; } /** * Pre-flight balance check result. Returned alongside the unsigned transaction * so the agent/user can see exactly what token balances are available and * whether the requested operation will succeed on-chain. */ export interface BalanceCheck { /** Wallet address that was checked. */ wallet: string; /** All token balances fetched (USDC, JITOSOL, WBTC, BONK, SOL). */ balances: TokenBalance[]; /** The token symbol required as collateral/funding for this operation. */ requiredToken: string; /** Human-readable amount required. */ requiredAmount: number; /** Human-readable balance available. */ availableBalance: number; /** True if available >= required. */ sufficient: boolean; /** Human-readable shortfall (0 if sufficient). */ shortfall: number; /** SOL balance for gas/fees. */ solBalance: number; /** True if SOL balance is enough for transaction fees (~0.005 SOL minimum). */ solSufficientForFees: boolean; } /** * Pool/custody metadata read from the on-chain custody account. * Included in UnsignedTransactionResult for open-position builders so the * agent/user can see leverage limits and open interest before signing. */ export interface PoolMetadata { /** Maximum initial leverage for new positions (human-readable, e.g. 100 = 100x). */ maxInitialLeverage: number; /** Maximum leverage after position is open (human-readable, e.g. 150 = 150x). */ maxLeverage: number; /** Maximum position size locked in USD (human-readable). */ maxPositionLockedUsd: number; /** Current open interest on the long side in USD (human-readable). */ openInterestLongUsd: number; /** Current open interest on the short side in USD (human-readable). */ openInterestShortUsd: number; } export interface AdrenaOraclePriceStatus { symbol: string; requiredFreshPrices: number; freshPrices: number; ready: boolean; sources: { symbol: string; feedId: number; priceUsd: number; confidenceUsd: number; timestamp: number; ageSeconds: number; fresh: boolean; }[]; } export interface AdrenaOracleReadiness { poolName: AdrenaPool; pool: string; oracle: string; ready: boolean; requiredSymbols: string[]; checkedAt: number; minAgree: number; stalenessSeconds: number; poolAllowsTrade: boolean; poolAllowsSwap: boolean; symbols: AdrenaOraclePriceStatus[]; missingSymbols: string[]; reason?: string; } export declare class AdrenaOracleReadinessError extends Error { readonly code = "AdrenaOracleReadinessBlocked"; readonly status = "blocked_before_build"; readonly safeToApprove = false; readonly approvalBlocked = true; readonly oracleReadiness: AdrenaOracleReadiness; readonly nextAction: string; constructor(readiness: AdrenaOracleReadiness); } /** * Encode a human leverage multiplier into Adrena's 1e4 BPS wire format. * Example: 3x => 30000, 100x => 1000000. */ export declare function encodeAdrenaLeverage(leverage: number): number; /** * Result of simulating a position open without building or serializing a transaction. * Free dry-run — no x402 charge, no transaction bytes returned. */ export interface SimulatePositionResult { /** Program simulation logs from the Adrena instruction. */ simulationLogs: string[]; /** Simulation error string if the transaction would fail on-chain. */ simulationError?: string; /** Compute units consumed by the simulated instructions. */ unitsConsumed?: number; /** True if the simulation succeeded (no error in simulation). */ wouldSucceed: boolean; /** Human-readable diagnostic for known Adrena simulation failures. */ simulationDiagnostic?: string; /** Pre-flight balance check for the collateral token. */ balanceCheck: BalanceCheck; /** Live Adrena oracle coverage for the exact pool/custodies used by this trade. */ oracleReadiness?: AdrenaOracleReadiness; } /** Result of building an unsigned transaction. */ export interface UnsignedTransactionResult { /** Base64-serialized unsigned transaction. */ transactionBase64: string; /** Transaction encoding. */ encoding: 'base64'; /** Machine-readable approval gate. UIs may show signing controls only when true. */ safeToApprove: true; /** Machine-readable negative approval gate. Successful builder results keep this false. */ approvalBlocked: false; /** Builder-side RPC simulation status for this exact unsigned transaction. */ simulationStatus: 'passed'; /** Fee payer public key. */ feePayer: string; /** Description of the instructions included. */ instructions: string[]; /** The position PDA if relevant. */ positionAddress?: string; /** Next tool to call for signing. */ nextTool: 'sap_payments_finalize_transaction'; /** Arguments to pass to the finalize tool. */ finalizeArgs: { transactionBase64: string; submit: boolean; }; /** Pre-flight balance check (present when the builder performed one). */ balanceCheck?: BalanceCheck; /** Pool/custody metadata (present for open-position builders). */ poolMetadata?: PoolMetadata; /** Requested leverage metadata for Adrena open-position builders. */ requestedLeverage?: { multiplier: number; encodedBps: number; scale: 'adrena_bps_1e4'; }; /** Warning message if balance is insufficient or other pre-flight concern. */ warning?: string; /** Pre-submit simulation logs from the builder (when available). */ simulationLogs?: string[]; /** Pre-submit simulation error (when simulation fails). */ simulationError?: string; /** Compute units consumed (from simulation). */ simulationUnitsConsumed?: number; /** Priority fee in micro-lamports applied to this transaction (0 = none). */ priorityFeeMicroLamports?: number; /** Live Adrena oracle coverage checked before returning signable transaction bytes. */ oracleReadiness?: AdrenaOracleReadiness; /** Present when the initial simulation hit a multi-oracle failure (6088 et * al) and the builder retried with the Switchboard refresh flow. The caller * must sign/submit `oracleRefresh.transactionBase64` BEFORE the trade tx * when `status === 'land-refresh-first'`. */ oracleRefresh?: { transactionBase64: string; quoteAccount: string; updateOraclePrepended: boolean; status: 'land-refresh-first' | 'healed'; }; } /** * Convert a bigint to a BN instance for Anchor instruction encoding. * Anchor 0.30.x uses @coral-xyz/borsh which requires BN, not native BigInt. * @param value — bigint value. * @returns BN instance. */ export declare function toBN(value: bigint): BN; /** * Convert a bigint or null to a BN or null for optional Anchor fields. * @param value — bigint or null. * @returns BN instance or null. */ export declare function toBNOrNull(value: bigint | null): BN | null; /** * Get pool public key by name. * @param poolName — Pool identifier. * @returns Pool public key. */ export declare function getPoolPublicKey(poolName: AdrenaPool): PublicKey; /** * Get custody public key by symbol. * @param symbol — Token symbol (e.g. "JITOSOL", "USDC"). * @param poolName — Pool identifier. * @returns Custody public key. */ export declare function getCustodyPublicKey(symbol: string, poolName?: AdrenaPool): PublicKey; /** * Get token mint by symbol. * @param symbol — Token symbol. * @returns Mint public key. */ export declare function getMintPublicKey(symbol: string): PublicKey; /** * Build a CreateAssociatedTokenAccountIdempotent instruction using @solana/spl-token. * This instruction creates the ATA if it doesn't exist, and is a no-op if it does. * * @param owner — Wallet public key that will own the ATA. * @param mint — Token mint public key. * @param payer — Fee payer public key (usually the owner). * @returns TransactionInstruction for CreateAssociatedTokenAccountIdempotent. */ export declare function createAtaIdempotentIx(owner: PublicKey, mint: PublicKey, payer: PublicKey): TransactionInstruction; /** * Fetch the current USD price for a token from the Adrena Data API. * Uses the same format as the Adrena SDK's DataApiClient.getLatestPrices(): * GET https://datapi.adrena.trade/last-trading-prices * Response: { data: { autonom: { prices: [{ symbol, price, exponent }] } } } * * The price is a string at 10-decimal precision; adjust by exponent to get USD float. * Returns the price as a BigInt scaled by 10^10 (PRICE_DECIMALS). * * @param principalToken — Token symbol (SOL, BONK, BTC, etc.) * JITOSOL maps to SOL (same as the SDK). * @returns Price as BigInt scaled by 10^10, or BigInt(0) if fetch fails. */ export declare function fetchOraclePrice(principalToken: string, side?: 'long' | 'short'): Promise; /** * Read the collateral custody token account address from the on-chain custody account. * The custody account stores the tokenAccount at byte offset 80 (after the 8-byte * Anchor discriminator + 2 boolean flags + 1 decimal byte + 5 padding + 32 pool). * * This is more reliable than PDA derivation because the seed layout may differ * from what the IDL declares. * * @param connection — Solana RPC connection. * @param custodyAddress — The custody PDA public key. * @returns The token account public key stored in the custody account. */ export declare function readCustodyTokenAccount(connection: Connection, custodyAddress: PublicKey): Promise; /** * Read pool/custody metadata from the on-chain custody account. * * Fields and their byte offsets (all little-endian): * - maxInitialLeverage: u32 at offset 176 (in BPS, 1000000 = 100x) * - maxLeverage: u32 at offset 180 (in BPS, 1000000 = 100x) * - maxPositionLockedUsd: u128 at offset 184 (scaled by 1e6) * - openInterestLongUsd: u128 at offset 408 (scaled by 1e6) * - openInterestShortUsd: u128 at offset 608 (scaled by 1e6) * * Leverage values are divided by 10000 for human-readable form. * USD values are divided by 1e6 for human-readable form. * * @param connection — Solana RPC connection. * @param custodyAddress — The custody PDA public key. * @returns PoolMetadata with human-readable values. */ export declare function readCustodyMetadata(connection: Connection, custodyAddress: PublicKey): Promise; interface AdrenaLimitedString { value?: readonly number[] | Uint8Array; length?: number; } interface DecodedAdrenaOraclePrice { price?: BN | number | string | bigint; confidence?: BN | number | string | bigint; timestamp?: BN | number | string; exponent?: number; feedId?: number; name?: AdrenaLimitedString; } export declare function decodeAdrenaLimitedString(value: unknown): string; export declare function readCustodyOracleSymbols(connection: Connection, custodyAddress: PublicKey): Promise; export declare function readPositionRequiredOracleSymbols(connection: Connection, principalToken: string, collateralToken: string, poolName: AdrenaPool): Promise; /** * Raw decoder for the Adrena oracle account v39 layout (verified on mainnet * against GEm9TZP7BL8rTz1JDy6X74PL595zr1putA9BXC8ehDmU). * * The Anchor coder with the vendored pre-v39 IDL silently mis-decodes this * account (slot layout shifted), producing `prices: []` even when the account * holds fresh prices. This parser reads the bytemuck C-repr layout directly: * * discriminator u8[8] (skipped) * bump u8 | version u8 | registered_prices_count u8 | pad u8[5] * updated_at i64 * prices[50] OraclePrice, each 64 bytes: * price u64 | confidence u64 | timestamp i64 | exponent i32 | * feed_id u8 | pad u8[3] | name u8[32] * * @param data — Full oracle account data (including 8-byte discriminator). * @returns Array of decoded prices (empty when the account is invalid). */ export declare function decodeAdrenaOraclePricesV39(data: Uint8Array): DecodedAdrenaOraclePrice[]; /** Normalize an oracle symbol: 'SOLUSD' → 'SOL', keep 'XAU'/'XAG'/'WTI' as-is. */ export declare function normalizeAdrenaOracleSymbol(symbol: string): string; export declare function readAdrenaOracleReadiness(connection: Connection, poolName: AdrenaPool, requiredSymbols: readonly string[]): Promise; export declare function readPositionOracleReadiness(connection: Connection, principalToken: string, collateralToken: string, poolName: AdrenaPool): Promise; export declare function assertAdrenaOracleReady(readiness: AdrenaOracleReadiness): void; /** * Validate that the requested leverage does not exceed the custody's * maxInitialLeverage. Throws a clear error if it does. * * @param leverage — Requested leverage (human-readable, e.g. 3 = 3x). * @param maxInitialLeverageBps — Max initial leverage in BPS (e.g. 1000000 = 100x). * @param principalToken — Token symbol for the error message. */ export declare function validateLeverage(leverage: number, maxInitialLeverageBps: number, principalToken: string): void; /** * Fetch all Adrena-relevant token balances for a wallet: USDC, JITOSOL, WBTC, BONK, and SOL. * * For SPL tokens, reads the Associated Token Account (ATA) balance via * `connection.getParsedTokenAccountsByOwner`. For SOL, reads lamports via * `connection.getBalance`. * * @param connection — Solana RPC connection. * @param owner — Wallet public key. * @returns Array of TokenBalance for each supported token (including zero balances). */ export declare function getWalletTokenBalances(connection: Connection, owner: PublicKey): Promise; /** * Pre-flight balance check: compare requested collateral/amount against the * wallet's actual token balance, and check SOL for fees. * * Returns a BalanceCheck object that can be embedded in the UnsignedTransactionResult * so the agent/user sees balances and warnings before signing. * * @param connection — Solana RPC connection. * @param owner — Wallet public key. * @param requiredToken — Token symbol required (e.g. "USDC", "JITOSOL"). * @param requiredAmount — Human-readable amount required. * @returns BalanceCheck with all balances and sufficiency flags. */ export declare function checkSufficientBalance(connection: Connection, owner: PublicKey, requiredToken: string, requiredAmount: number): Promise; /** * Check if a user profile PDA exists on-chain. If it doesn't, build an * init_user_profile instruction to create it before any Adrena position operation. * * @param connection — Solana RPC connection. * @param owner — Wallet public key that needs a user profile. * @returns Array of pre-instructions (empty if profile exists, or [initUserProfile] if not). */ export declare function ensureUserProfileInstructions(connection: Connection, owner: PublicKey): Promise; /** * Always return a CreateAssociatedTokenAccountIdempotent instruction. * The instruction is a no-op if the ATA already exists, so it's safe to always include. * * @param _connection — Unused (kept for API compatibility). * @param owner — Wallet public key. * @param mint — Token mint public key. * @param payer — Fee payer public key. * @returns Array with a single CreateAssociatedTokenAccountIdempotent instruction. */ export declare function ensureAtaInstructions(_connection: Connection, owner: PublicKey, mint: PublicKey, payer: PublicKey): Promise; /** * Create an Anchor Program instance from the vendored IDL. * @param connection — Solana RPC connection. * @returns Anchor Program instance. */ export declare function createAdrenaProgram(connection: Connection): Program; /** * Convert an Anchor instruction to a @solana/web3.js TransactionInstruction. * Anchor's `Instruction` namespace returns instructions with keys and data * that can be directly mapped to TransactionInstruction. * @param program — Anchor Program instance. * @param ixName — Instruction name (camelCase). * @param args — Instruction arguments. * @param accounts — Account public keys by name. * @returns web3.js TransactionInstruction. */ export declare function buildInstruction(program: Program, ixName: string, args: unknown[], accounts: Record): Promise; /** * Serialize an unsigned transaction with latest blockhash. * @param connection — Solana RPC connection. * @param feePayer — Fee payer public key. * @param instructions — Transaction instructions. * @returns Base64-serialized unsigned transaction. */ /** Result of serializeUnsignedTx — includes the base64 transaction and simulation metadata. */ export interface SerializeResult { transactionBase64: string; simulationLogs?: string[]; simulationError?: string; simulationUnitsConsumed?: number; priorityFeeMicroLamports?: number; } export declare function describeAdrenaSimulationFailure(result: Pick, instructionNames: readonly string[]): string | undefined; export declare function assertAdrenaSimulationPassed(result: Pick, instructionNames: readonly string[]): void; export declare function serializeUnsignedTx(connection: Connection, feePayer: PublicKey, instructions: TransactionInstruction[]): Promise; /** * Build the result object for a builder function. * @param transactionBase64 — Serialized unsigned transaction. * @param feePayer — Fee payer public key. * @param instructionNames — List of instruction names. * @param positionAddress — Optional position PDA. * @param balanceCheck — Optional pre-flight balance check result. * @param warning — Optional warning message (e.g. insufficient balance). * @param poolMetadata — Optional pool/custody metadata (for open-position builders). * @returns Unsigned transaction result. */ export declare function buildResult(transactionBase64: string, feePayer: PublicKey, instructionNames: string[], positionAddress?: PublicKey, balanceCheck?: BalanceCheck, warning?: string, poolMetadata?: PoolMetadata, requestedLeverage?: number, simulation?: Pick, oracleReadiness?: AdrenaOracleReadiness): UnsignedTransactionResult; export { ADRENA_CUSTODIES, ADRENA_TOKEN_MINTS, ADRENA_PROGRAM_ID, ADRENA_MAIN_POOL_ADDRESS, ADRENA_COMMODITIES_POOL_ADDRESS, } from './adrena-constants.js'; export { deriveCortexPda, deriveOraclePda, deriveTransferAuthorityPda, deriveUserProfilePda, derivePositionPda, deriveLimitOrderBookPda, deriveCollateralEscrowPda, deriveLpTokenMintPda, deriveStakingPda, deriveUserStakingPda, deriveGenesisLockPda, deriveLmTokenTreasuryPda, deriveLmTokenMintPda, deriveGovernanceTokenMintPda, deriveStakingStakedTokenVaultPda, deriveStakingRewardTokenVaultPda, deriveStakingLmRewardTokenVaultPda, deriveAta, } from './adrena-pda.js'; //# sourceMappingURL=adrena-builder-core.d.ts.map