You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:07:27