如何用JS解码Solana的compiledInstructions获取代币交易信息
解码Solana交易指令提取代币与金额
核心步骤
1. 定位目标程序ID
用第三条指令的programIdIndex:7,从完整交易的message.accountKeys数组中取出对应的PublicKey,确认该程序所属的协议(比如Raydium、Serum等DEX)——不同协议的指令格式完全不同,这是解码的关键前提。
2. 解析指令数据Buffer
根据协议的指令格式手动解码,或借助对应SDK/IDL自动解码:
手动解码示例(以Raydium Swap指令为例)
假设第三条指令是Raydium的Swap操作,其指令数据结构包含amount_in、amount_out_min等参数:
// 从compiledInstructions中取出第三条的data Buffer const instructionData = compiledInstructions[2].data; // 前8字节是指令鉴别器(用于区分不同指令类型) const discriminator = instructionData.slice(0, 8); // 验证鉴别器是否匹配目标指令(比如Raydium Swap的鉴别器是0x52e177e74e1d2d46) console.log(discriminator.toString('hex')); // 输出52e177e74e1d2d46,确认是Swap指令 // 提取输入金额(u64类型,小端字节序) const amountIn = instructionData.slice(8, 16).readBigUInt64LE(); // 提取最小输出金额(u64类型) const amountOutMin = instructionData.slice(16, 24).readBigUInt64LE(); // 金额需要除以代币的decimals(比如USDC是6,SOL是9),才能得到可读数值 // 这里需要先获取对应代币的decimals,可通过Mint账户查询 const readableAmount = Number(amountOutMin) / Math.pow(10, decimals);
借助Anchor IDL自动解码
如果目标程序是用Anchor开发的(比如多数DEX),可以通过IDL直接解码:
import { Program, AnchorProvider } from '@project-serum/anchor'; // 导入对应程序的IDL文件(可从Solscan或项目GitHub获取) import ammIdl from './raydium-amm-idl.json'; // 初始化Provider和Program const provider = AnchorProvider.local(); const programId = transaction.message.accountKeys[7]; // 目标程序ID const program = new Program(ammIdl, programId, provider); // 解码指令 const decoded = program.instruction.decode( compiledInstructions[2].data, compiledInstructions[2].accountKeyIndexes.map(idx => transaction.message.accountKeys[idx]) ); // 直接获取解码后的参数 console.log('最小购买金额:', decoded.amountOutMin.toString());
3. 提取购买的代币地址
第三条指令的accountKeyIndexes数组中的索引,对应交易message.accountKeys里的账户。以Swap指令为例,输出代币的Mint账户就是你购买的代币地址,通常在账户列表的特定位置(比如Raydium Swap的输出代币Mint是第8个账户索引):
// 假设accountKeyIndexes中第8个索引对应输出代币Mint const mintIndex = compiledInstructions[2].accountKeyIndexes[8]; const purchasedTokenMint = transaction.message.accountKeys[mintIndex].toBase58(); console.log('购买的代币地址:', purchasedTokenMint);
4. 补充代币精度(Decimals)
通过代币Mint地址查询其decimals字段(可通过Solana RPC的getAccountInfo方法,或@solana/spl-token库的getMint方法):
import { getMint } from '@solana/spl-token'; import { Connection } from '@solana/web3.js'; const connection = new Connection('https://api.mainnet-beta.solana.com'); const mintInfo = await getMint(connection, new PublicKey(purchasedTokenMint)); const decimals = mintInfo.decimals;
关键提示
- 不同协议的指令格式差异极大,必须先确认
programIdIndex:7对应的程序是什么,才能正确解码数据。 - 如果
accountKeyIndexes是压缩数组(显示为[Array]),需要展开查看完整索引列表,才能对应到正确的代币Mint账户。 - 金额存储为u64类型,必须除以代币的decimals才能得到人类可读的数值。
内容的提问来源于stack exchange,提问作者Matěj Pátek
相关产品推荐
相关产品推荐

