Raydium DEX上Solana代币兑换代码报错:无效公钥问题排查
Solana Raydium 兑换代码 PublicKey 错误排查与修复
问题描述
编写Raydium上Solana代币兑换测试代码时遇到invalid public key错误,代码及错误信息如下:
测试代码
const { Connection, Keypair, PublicKey } = require('@solana/web3.js'); const { Liquidity, TokenAmount, Token, Percent } = require('@raydium-io/raydium-sdk'); const devnetConnection = new Connection('https://api.devnet.solana.com'); const privateKey = []; // PRIVATE KEY HIDDEN const wallet = Keypair.fromSecretKey(new Uint8Array(privateKey)); const OWNER = '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'; const TOKEN = 'EP2ib6dYdEeqD8MfE2ezHCxX3kP3K2eLKkirfPm5eyMx'; const SOL = 'So11111111111111111111111111111111111111112'; const PAIR = 'CQurpF3WS3yEqFEt1Bu8s5zmZqznQG3EJkcYvsyg3sLc'; async function main() { const poolKeys = { id: new PublicKey(OWNER), }; const tokenA = new Token(devnetConnection, new PublicKey(SOL), 9, wallet.publicKey); const tokenB = new Token(devnetConnection, new PublicKey(TOKEN), 6, wallet.publicKey); const rawAmountIn = 1; const amountIn = new TokenAmount(tokenA, rawAmountIn * 10**tokenA.decimals, false); const slippage = new Percent(50, 10000); const poolInfo = await Liquidity.fetchInfo(devnetConnection, poolKeys); const { minAmountOut } = Liquidity.computeAmountOut(poolInfo, amountIn, tokenB, slippage); const { transaction, signers } = await Liquidity.makeSwapTransaction({ connection: devnetConnection, poolKeys, userKeys: { owner: wallet.publicKey, }, amountIn, amountOut: minAmountOut, fixedSide: 'in', }); const signature = await devnetConnection.sendTransaction(transaction, [wallet, ...signers]); console.log(`Transaction hash: ${signature}`); await devnetConnection.confirmTransaction(signature); console.log(`Transaction confirmed: ${signature}`); } main().catch(error => { console.error(error); });
错误信息
reason: 'invalid public key', code: 'INVALID_ARGUMENT', argument: 'publicKey',
需求:找出代码遗漏点,提供可运行的极简测试代码,同时说明信息获取渠道。
错误原因与修复
poolKeys参数不完整:Raydium SDK的Liquidity.fetchInfo和makeSwapTransaction需要完整的池密钥集合(含代币账户、LP账户、授权账户等),仅传入id会导致公钥解析失败,需通过SDK工具函数获取完整池信息。- Token类初始化参数错误:
Token构造函数第四个参数应为代币的mint地址,而非钱包公钥,错误传入钱包地址会触发公钥验证失败。 - 缺少用户代币账户信息:
userKeys需包含用户的输入/输出代币账户地址,仅传owner无法让交易定位用户的代币余额。
可运行的极简测试代码
const { Connection, Keypair, PublicKey } = require('@solana/web3.js'); const { Liquidity, TokenAmount, Token, Percent, TokenAccount } = require('@raydium-io/raydium-sdk'); // 初始化连接和钱包 const devnetConnection = new Connection('https://api.devnet.solana.com'); const privateKey = []; // 替换为你的devnet钱包私钥数组 const wallet = Keypair.fromSecretKey(new Uint8Array(privateKey)); // 代币和池信息(devnet环境) const SOL_MINT = new PublicKey('So11111111111111111111111111111111111111112'); const TEST_TOKEN_MINT = new PublicKey('EP2ib6dYdEeqD8MfE2ezHCxX3kP3K2eLKkirfPm5eyMx'); const PAIR_ID = new PublicKey('CQurpF3WS3yEqFEt1Bu8s5zmZqznQG3EJkcYvsyg3sLc'); async function main() { // 1. 获取完整的池密钥信息 const poolKeys = await Liquidity.fetchPoolKeys(devnetConnection, PAIR_ID); if (!poolKeys) throw new Error('无法获取池信息'); // 2. 初始化代币对象(第四个参数是mint地址) const solToken = new Token(devnetConnection, SOL_MINT, 9, SOL_MINT); const testToken = new Token(devnetConnection, TEST_TOKEN_MINT, 6, TEST_TOKEN_MINT); // 3. 获取用户的代币账户 const userSolAccount = await TokenAccount.getAssociatedTokenAccount(devnetConnection, wallet.publicKey, SOL_MINT); const userTestTokenAccount = await TokenAccount.getAssociatedTokenAccount(devnetConnection, wallet.publicKey, TEST_TOKEN_MINT); // 4. 定义兑换参数 const rawAmountIn = 0.01; // 兑换0.01 SOL const amountIn = new TokenAmount(solToken, rawAmountIn * 10**solToken.decimals, false); const slippage = new Percent(50, 10000); // 0.5%滑点 // 5. 获取池信息并计算最小输出 const poolInfo = await Liquidity.fetchInfo(devnetConnection, poolKeys); const { minAmountOut } = Liquidity.computeAmountOut(poolInfo, amountIn, testToken, slippage); // 6. 构建兑换交易 const { transaction, signers } = await Liquidity.makeSwapTransaction({ connection: devnetConnection, poolKeys, userKeys: { owner: wallet.publicKey, source: userSolAccount.address, destination: userTestTokenAccount.address, // SOL兑换需额外传入钱包地址作为SOL源账户 ...(solToken.isSOL ? { sourceSOL: wallet.publicKey } : {}), }, amountIn, amountOut: minAmountOut, fixedSide: 'in', }); // 7. 发送并确认交易 const signature = await devnetConnection.sendTransaction(transaction, [wallet, ...signers], { skipPreflight: false }); console.log(`交易哈希: ${signature}`); await devnetConnection.confirmTransaction(signature, 'confirmed'); console.log(`交易已确认: ${signature}`); } main().catch(error => { console.error('错误:', error); });
信息获取渠道
- Raydium官方GitHub仓库的examples目录:包含兑换、添加流动性等完整交易示例
- Solana官方文档:了解PublicKey、TokenAccount等核心概念的验证规则
- Raydium SDK源码注释:直接查看函数的参数要求和返回值结构
内容的提问来源于stack exchange,提问作者Nico Nico
相关产品推荐
相关产品推荐

