如何通过API实现Solana交易后端钱包签名代付
Solana 后端钱包代付交易手续费落地实现
你说的在sendAndConfirmTransaction调用前提取构造好的交易的思路完全可行,整个流程不需要改链上程序,只需要拆分前后端的交易签名逻辑即可,具体落地步骤如下:
前端逻辑改造
- 先单独构造交易对象,不要直接触发发送逻辑:先从RPC节点拿最新的区块哈希,提前把后端付费钱包的公钥设为交易的
feePayer,再把你的业务指令(比如示例里的hello world指令)添加到交易里,这一步不要做任何签名操作。
对应示例代码修改如下:// 替换原来直接调用sendAndConfirmTransaction的逻辑 const latestBlockhash = await connection.getLatestBlockhash('confirmed'); // 组装交易,指定付费方为后端钱包公钥 const tx = new Transaction({ feePayer: backendFeePayerPubkey, // 可提前通过配置或内部接口拿到后端付费钱包公钥 blockhash: latestBlockhash.blockhash, lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, }).add( // 这里放你的业务指令,也就是示例里构造的TransactionInstruction new TransactionInstruction({ keys: [{pubkey: greetedPubkey, isSigner: false, isWritable: true}], programId, data: createSetInstruction() }) ); - 把未完成签名的交易序列化后传给后端:调用
tx.serialize({requireAllSignatures: false})把交易转成二进制,再转成base64字符串通过POST接口发给后端,不要直接传JS对象避免序列化格式不兼容。 - 拿到后端返回的带付费方签名的交易后,先反序列化为Transaction实例,再调起当前用户连接的钱包(比如Phantom、Solflare)的
signTransaction方法,让用户完成自己需要的签名。 - 等所有签名凑齐后,调用
connection.sendRawTransaction(tx.serialize())把交易提交到链上,再调用confirmTransaction等待交易确认即可。
后端逻辑改造
- 接口收到前端传的序列化交易后,先做严格的安全校验:首先确认交易的
feePayer字段确实是自身部署的付费钱包地址,再逐笔校验交易里的所有指令都在你允许的业务指令白名单内,禁止给任意转账、未知合约调用的交易签名。这步是核心风控逻辑,绝对不能省略,否则会出现恶意构造交易盗刷付费钱包余额的风险
- 校验通过后,用服务端存储的付费钱包密钥对交易签名,注意不要修改交易本身的内容,只追加签名即可,Node端参考代码如下:
import { Transaction, Keypair } from '@solana/web3.js'; // 从环境变量/密钥管理服务加载付费钱包密钥,不要硬编码在代码里 const feePayerKeypair = Keypair.fromSecretKey( Uint8Array.from(JSON.parse(process.env.SOL_FEE_PAYER_SECRET)) ); // 反序列化前端传来的交易 const tx = Transaction.from(Buffer.from(frontendTxBase64, 'base64')); // 追加付费方签名 tx.sign(feePayerKeypair); // 把签完的交易序列化回base64返回给前端 const signedTxBase64 = tx.serialize({ requireAllSignatures: false }).toString('base64'); return { signedTx: signedTxBase64 }; - 后端只负责签名返回,不要提前把交易发上链,必须等前端凑齐所有用户签名后再由前端提交。
注意事项
- Solana区块哈希有效期约60秒,前端构造交易、后端签名、用户签名三个环节不要加过长的等待逻辑,否则会触发区块哈希过期错误导致交易失败。
- 构造业务指令时,如果某个账号需要签名(比如用户作为资产转出方、权限修改方),一定要把对应账号的
isSigner字段设为true,否则就算用户签了名交易也会验证失败。 - 如果用Solana V0版本化交易,逻辑完全一致,只需要把Transaction类换成VersionedTransaction类,签名方法对应调整即可。
内容的提问来源于stack exchange,提问作者alessandro buffoli
相关产品推荐
相关产品推荐

