USDT网页端转账正常,Tonkeeper移动端钱包转账失败排查
Tonkeeper移动端Jetton(USDT)转账失败问题排查与解决
问题描述
- 浏览器端通过Tonkeeper调用指定USDT转账Payload可成功完成转账
- Tonkeeper移动端APP执行时,交易生成哈希(解码BOC可见),但USDT未到账,操作前即显示失败
- 怀疑Payload或BOC生成存在跨端兼容问题,需实现跨端正常转账并验证到账状态
原实现代码
// Define the Jetton transfer payload const buildJettonTransferPayload = (receiverAddress, amount) => { const depositAmount = toNano(amount); // Convert the amount to nanoTON // Check if receiverAddress is valid let parsedReceiverAddress; try { parsedReceiverAddress = Address.parse(receiverAddress); } catch (error) { throw new Error("Invalid receiver address"); } // Construct the Jetton transfer payload const body = beginCell() .storeUint(0xf8a7ea5, 32) // Operation ID for Jetton transfer (USDT) .storeUint(0, 64) // Query ID .storeCoins(depositAmount) // Deposit amount (in nanoTON) .storeAddress(parsedReceiverAddress) // Receiver address .storeMaybeRef(null) // No custom payload .storeCoins(toNano(0.03)) // Forward TON amount (0.03 TON for fees) .storeMaybeRef(beginCell().storeStringTail('Transfer USDT').endCell()) // Forward payload .endCell(); return body; }; const myTransaction = (receiverAddress, amount) => ({ validUntil: Math.floor(Date.now() / 1000) + 360, // Transaction expiry messages: [ { address: usdtContractAddress, // USDT Jetton contract address amount: toNano(0.03), // Commission fee (0.03 TON) payload: buildJettonTransferPayload(receiverAddress, amount).toBoc().toString("base64"), // Base64 encoded Jetton transfer payload }, ], });
问题排查与修复
1. 操作ID兼容性问题
原代码使用的0xf8a7ea5是特定USDT合约的转账操作ID,但Tonkeeper移动端对标准Jetton转账操作ID0x178d4519兼容性更好,替换为标准ID:
.storeUint(0x178d4519, 32) // 标准Jetton转账操作ID
2. Forward金额优化
部分Jetton合约对forward金额的下限要求更严格,原代码的0.03 TON虽足够,但调整为0.001 TON可适配更多合约场景,同时确保覆盖接收方合约处理费用:
.storeCoins(toNano(0.001)) // 调整为更低的forward费用,提升兼容性
3. BOC编码跨端统一
浏览器与移动端Base64编码可能存在换行符差异,生成BOC时去除换行符:
payload: buildJettonTransferPayload(receiverAddress, amount).toBoc().toString("base64").replace(/\n/g, '')
4. 延长交易有效期
原代码360秒有效期较短,移动端易因网络延迟导致交易过期,延长至1800秒(30分钟):
validUntil: Math.floor(Date.now() / 1000) + 1800, // 延长交易有效期至30分钟
修复后的完整代码
// 构建Jetton转账Payload const buildJettonTransferPayload = (receiverAddress, amount) => { const depositAmount = toNano(amount); // 转换金额为nanoTON // 验证接收地址有效性 let parsedReceiverAddress; try { parsedReceiverAddress = Address.parse(receiverAddress); } catch (error) { throw new Error("无效的接收地址"); } // 构造Jetton转账Payload const body = beginCell() .storeUint(0x178d4519, 32) // 标准Jetton转账操作ID .storeUint(0, 64) // Query ID .storeCoins(depositAmount) // 转账金额(nanoTON) .storeAddress(parsedReceiverAddress) // 接收方地址 .storeMaybeRef(null) // 无自定义Payload .storeCoins(toNano(0.001)) // Forward TON金额(覆盖接收方合约费用) .storeMaybeRef(beginCell().storeStringTail('Transfer USDT').endCell()) // Forward备注 .endCell(); return body; }; const myTransaction = (receiverAddress, amount) => ({ validUntil: Math.floor(Date.now() / 1000) + 1800, // 交易有效期30分钟 messages: [ { address: usdtContractAddress, // USDT Jetton合约地址 amount: toNano(0.03), // 交易手续费(0.03 TON) payload: buildJettonTransferPayload(receiverAddress, amount).toBoc().toString("base64").replace(/\n/g, ''), // 无换行的Base64编码BOC }, ], });
USDT到账状态验证
- 调用Jetton合约的
get_wallet_address方法,获取转出方与转入方的Jetton钱包地址 - 查询转入方Jetton钱包的
get_balance方法,对比转账前后的余额变化 - 通过TON区块链浏览器查询交易哈希,确认交易是否成功上链执行
内容的提问来源于stack exchange,提问作者Pushkar Nikumb
相关产品推荐
相关产品推荐

