import { PublicKey, TransactionInstruction } from "@solana/web3.js"; import BN from "bn.js"; import type { PitProgram } from "../program.js"; import { TOKEN_2022_PROGRAM_ID } from "../constants.js"; import { PoolType } from "../types.js"; import { getMarketAddress } from "../accounts/pda.js"; /** * Parameters for creating a trade instruction */ export interface TradeParams { /** Week number of the market */ weekNumber: number; /** Pool type (High or Low) */ poolType: PoolType; /** Strike index (0, 1, or 2) */ strikeIndex: number; /** Whether this is a HIT token (true) or MISS token (false) */ isHit: boolean; /** Amount of tokens to buy/sell (in token decimals, 9 decimals) */ amount: BN; /** Whether this is a buy (true) or sell (false) */ isBuy: boolean; /** Slippage protection: max cost for buy (lamports), min refund for sell (lamports) */ limitLamports: BN; /** User's public key (signer) */ user: PublicKey; /** User's token account for the specific Hit/Miss token */ userTokenAccount: PublicKey; /** User's wSOL account */ userWsolAccount: PublicKey; /** wSOL vault (from MarketState.wsolVault) */ wsolVault: PublicKey; /** Token mint for the specific Hit/Miss token */ tokenMint: PublicKey; /** wSOL mint address */ wsolMint: PublicKey; /** Token program (usually SPL Token) */ tokenProgram: PublicKey; } /** * Create a trade instruction for buying or selling Hit/Miss tokens * * @param program - Anchor Program instance * @param params - Trade parameters * @returns Promise resolving to TransactionInstruction * * @example * ```typescript * import { createProgram, createTradeInstruction, PoolType } from "@pit-protocol/sdk"; * * const program = createProgram(provider); * const ix = await createTradeInstruction(program, { * weekNumber: 1, * poolType: PoolType.High, * strikeIndex: 0, * isHit: true, * amount: new BN(1_000_000_000), // 1 token * isBuy: true, * limitLamports: new BN(10_000_000_000), // 10 SOL max cost (for buy) * user: wallet.publicKey, * userTokenAccount: hitTokenAta, * userWsolAccount: wsolAta, * wsolVault: market.wsolVault, * tokenMint: hitMint, * wsolMint: WSOL_MINT, * tokenProgram: TOKEN_PROGRAM_ID, * }); * * // User sends the transaction * const tx = new Transaction().add(ix); * await sendAndConfirmTransaction(connection, tx, [wallet]); * ``` */ export async function createTradeInstruction( program: PitProgram, params: TradeParams ): Promise { const { weekNumber, poolType, strikeIndex, isHit, amount, isBuy, limitLamports, user, userTokenAccount, userWsolAccount, wsolVault, tokenMint, wsolMint, tokenProgram, } = params; // Validate parameters if (strikeIndex < 0 || strikeIndex > 2) { throw new Error("strikeIndex must be 0, 1, or 2"); } if (amount.lte(new BN(0))) { throw new Error("amount must be greater than 0"); } const marketState = getMarketAddress(weekNumber); // Convert PoolType to IDL format (use type assertion for Anchor enum compatibility) const poolTypeArg = (poolType === PoolType.High ? { high: {} } : { low: {} }) as | { high: Record } | { low: Record }; return await program.methods .trade(poolTypeArg, strikeIndex, isHit, amount, isBuy, limitLamports) .accountsPartial({ marketState, user, userTokenAccount, userWsolAccount, wsolMint, wsolVault, tokenMint, tokenProgram, token2022Program: TOKEN_2022_PROGRAM_ID, }) .instruction(); }