Telegram订阅机器人集成USDT TRC20支付的技术难题求助
实现Telegram机器人集成USDT TRC20支付方案(无第三方支付网关)
1. 生成用户专属USDT TRC20地址
直接用Tron官方SDK(比如tronweb)生成独立地址对,每个用户发起支付请求时生成唯一地址,关联用户ID、应付金额、过期时间存入数据库(如MySQL/Redis)即可。
- 代码示例(Node.js):
const TronWeb = require('tronweb'); const tronWeb = new TronWeb({ fullHost: 'https://api.trongrid.io', headers: { "TRON-PRO-API-KEY": "你的TronGrid API密钥" } }); // 生成用户专属地址并关联订单 async function generateUserPaymentAddress(userId, amountDue) { const account = await tronWeb.createAccount(); // 存入数据库:userId, address=account.address.base58, privateKey=account.privateKey, amountDue, expiresAt=Date.now()+900000(15分钟过期), status='pending' return account.address.base58; }
- 核心:用户地址的私钥必须加密存储,后续归集转账要用到。
2. 支付状态校验
两种方案可选,按需选择:
方案A:定时轮询
用定时器定期扫描未完成订单,调用TronGrid API查询用户地址的USDT余额:
async function verifyPayment(userId) { const order = await db.query('SELECT * FROM payment_orders WHERE userId = ? AND status = "pending"', [userId]); if (!order) return; // USDT TRC20合约地址固定为TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t const usdtBalance = await tronWeb.trx.getTokenBalance(order.address, 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'); const actualAmount = usdtBalance / 1e6; // 转换为USDT单位(6位小数) if (actualAmount >= order.amountDue) { // 标记支付完成,授予频道权限 await db.query('UPDATE payment_orders SET status = "completed" WHERE id = ?', [order.id]); await telegramBot.addChatMember('你的私密频道ID', userId); } else if (Date.now() > order.expiresAt) { // 订单过期,标记失效 await db.query('UPDATE payment_orders SET status = "expired" WHERE id = ?', [order.id]); } } // 每30秒轮询一次 setInterval(() => { db.query('SELECT userId FROM payment_orders WHERE status = "pending"').then(users => { users.forEach(user => verifyPayment(user.userId)); }); }, 30000);
方案B:实时事件监听
通过TronGrid的WebSocket订阅用户地址的USDT转账事件,比轮询更高效:
const socket = tronWeb.eventServer.subscribe('transfer', { contract: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', recipient: '用户地址' }); socket.on('message', async (data) => { const userId = await db.query('SELECT userId FROM payment_orders WHERE address = ? AND status = "pending"', [data.result.to]); if (userId) { const amount = parseInt(data.result.value) / 1e6; const order = await db.query('SELECT amountDue FROM payment_orders WHERE userId = ?', [userId]); if (amount >= order.amountDue) { // 执行支付完成逻辑 } } });
- 注意:校验时最好等待1-2个区块确认,避免链上交易回滚导致误判。
3. USDT归集到主地址
用户支付完成后,用用户地址的私钥签名转账交易,将USDT转到你的主地址:
async function collectUSDT(userAddress, userPrivateKey, mainAddress) { const usdtBalance = await tronWeb.trx.getTokenBalance(userAddress, 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'); if (usdtBalance <= 0) return; try { const tx = await tronWeb.transactionBuilder.sendToken( mainAddress, usdtBalance, // 全额归集,已为最小单位 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', userAddress ); const signedTx = await tronWeb.trx.sign(tx, userPrivateKey); await tronWeb.trx.sendRawTransaction(signedTx); // 标记订单为已归集 await db.query('UPDATE payment_orders SET collected = 1 WHERE address = ?', [userAddress]); } catch (err) { console.error('归集失败:', err); } }
- 关键:用户地址必须有足够TRX作为燃料费才能转账,所以要么生成地址时预存少量TRX(比如0.01 TRX),要么在支付提示里告知用户自行存入。
4. 核心注意事项
- 安全性:用户私钥必须加密存储,主地址私钥用环境变量或密钥管理服务托管,绝对不能硬编码。
- 过期机制:设置合理的订单过期时间(比如15-30分钟),清理无效订单。
- 异常处理:处理链上交易失败、API请求超时等情况,避免机器人逻辑卡死。
内容的提问来源于stack exchange,提问作者CrazyChicken
相关产品推荐
相关产品推荐

