创建 TRC20 代币交易
本教程介绍 Chaingateway V2 API 中与 TRC20 相关的接口:创建 TRON 地址、读取代币合约、查询代币余额,以及发送 TRC20 转账。示例代码涵盖 Shell(cURL)、PHP(Guzzle)、Python(Requests)和 JavaScript(Axios)。
有关获取 API key 和了解授权的信息,请参阅 Chaingateway 文档的快速入门部分。
这个 API 能做什么,不能做什么
Section titled “这个 API 能做什么,不能做什么”这个 API 没有用于编译或部署智能合约的接口。没有任何路由可以把一个新的 TRC20 合约发布到 TRON 网络上,所有 TRON 相关接口也都不接受合约字节码。每一个 TRC20 路由都需要传入一个已经存在于链上的代币的 contractaddress,无论是 USDT 还是其他任何 TRC20 代币,都是如此。
如果你要找的是部署自己代币合约的方法,这个 API 不适合这一步。合约部署完成之后,下面这些接口涵盖了大多数集成实际需要的部分:地址、余额、转账和通知。
| 你想做什么 | 接口 |
|---|---|
| 创建一个 TRON 地址 | POST /v2/tron/addresses |
| 导入已有私钥 | POST /v2/tron/addresses/import |
| 读取名称、符号、精度和总供应量 | GET /v2/tron/trc20/{contract_address} |
| 查询代币余额 | GET /v2/tron/balances/{address}/trc20/{contract_address} |
| 发送 TRC20 转账 | POST /v2/tron/transactions/trc20 |
| 构建但不广播一笔转账 | POST /v2/tron/transactions/trc20/build |
| 广播你自己签名的交易 | POST /v2/tron/transactions/broadcast |
| 接收关于代币入账的通知 | POST /v2/tron/webhooks |
第一步:创建 TRON 地址
Section titled “第一步:创建 TRON 地址”发送地址必须是 Chaingateway 已知的地址。你可以通过 API 创建一个,也可以通过 POST /v2/tron/addresses/import 导入一个已有的私钥。
如果你传入 password,私钥会被加密保存,之后你用这个密码为交易签名。如果不传密码,响应中会直接包含私钥本身,此后每次交易请求都需要附带这个私钥。密码方式的详细说明见钱包管理。
curl --request POST\ --url https://api.chaingateway.io/v2/tron/addresses\ --header 'Accept: application/json'\ --header 'content-type: application/json'\ --header 'Authorization: YOUR_API_TOKEN'\ --data '{"password":"test123"}'import requests
url = "https://api.chaingateway.io/v2/tron/addresses"payload = {"password": "test123"}headers = { 'Accept': 'application/json', 'content-type': 'application/json', 'Authorization': 'YOUR_API_TOKEN'}
response = requests.post(url, json=payload, headers=headers)print(response.json())const axios = require('axios');
const url = 'https://api.chaingateway.io/v2/tron/addresses';const payload = { password: 'test123' };const headers = { 'Accept': 'application/json', 'content-type': 'application/json', 'Authorization': 'YOUR_API_TOKEN'};
axios.post(url, payload, { headers }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });<?phprequire 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client();$response = $client->post('https://api.chaingateway.io/v2/tron/addresses', [ 'headers' => [ 'Accept' => 'application/json', 'content-type' => 'application/json', 'Authorization' => 'YOUR_API_TOKEN', ], 'json' => [ 'password' => 'test123' ]]);
echo $response->getBody();?>响应中包含新地址:
{ "status": 201, "ok": true, "message": "Address created", "data": [ { "privateKey": "59f1c6200e01a2ca9471411f10198bfa63678d0e87cc2ca30f9c4a68dee78edc", "publicKey": "040fe6e677442c36f7fdd5535ba3ff1cef0110d78363420f7e24b65298990e3467aed68b9a67e1396d84753db25b32a2fa3e1fc0a673f01638e9bcfab2d8f4ceb5", "hexAddress": "41a56a6505ffbee78eb916dd44f4846874deddaebd", "address": "TR3qx91smURF3R455V1ubqtoUsZbgqikfg" } ]}Chaingateway 不存储密码。密码一旦丢失,钱包也就随之丢失。
第二步:读取代币合约
Section titled “第二步:读取代币合约”在转移代币之前,先读取它的合约。decimals 是你最常用到的字段,因为它告诉你链上的原始余额该如何换算成用户看到的金额。
curl --request GET\ --url https://api.chaingateway.io/v2/tron/trc20/TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t\ --header 'Accept: application/json'\ --header 'Authorization: YOUR_API_TOKEN'{ "status": 200, "ok": true, "message": "TRC20 contract fetched", "data": { "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "symbol": "USDT", "name": "TetherUSD", "totalSupply": "61742996582033118", "decimals": "6" }}一个未知的或非 TRC20 的合约地址会返回状态码 400,消息为 Error fetching TRC20 contract。
第三步:查询代币余额
Section titled “第三步:查询代币余额”curl --request GET\ --url https://api.chaingateway.io/v2/tron/balances/TVF2Mp9QY7FEGTnr3DBpFLobA6jguHyMvi/trc20/TXLAQ63Xg1NAzckPwKHvzw7CSEmLMEqcdj\ --header 'Accept: application/json'\ --header 'Authorization: YOUR_API_TOKEN'{ "status": 200, "ok": true, "message": "TRC20 balance fetched", "data": { "tronaddress": "TVF2Mp9QY7FEGTnr3DBpFLobA6jguHyMvi", "decimals": 6, "balance": "1000000000000000000", "contractaddress": "TXLAQ63Xg1NAzckPwKHvzw7CSEmLMEqcdj" }}balance 字段是原始整数值。将它除以 10 的 decimals 次方,即可得到人类可读的金额。
第四步:发送 TRC20 转账
Section titled “第四步:发送 TRC20 转账”POST /v2/tron/transactions/trc20 需要 from、to、contractaddress 和 amount。用于签名的参数二选一:如果地址是用密码创建的,就传 password;否则传 privatekey。
- from:发送方的 TRON 地址。
- to:接收方的 TRON 地址。
- contractaddress:代币的合约地址。
- amount:要发送的金额。
- password:受密码保护的 Chaingateway 地址的密码。当没有提供
privatekey时为必填项。 - privatekey:发送方的私钥,适用于创建或导入时未设置密码的地址。
curl --request POST\ --url https://api.chaingateway.io/v2/tron/transactions/trc20\ --header 'Accept: application/json'\ --header 'content-type: application/json'\ --header 'Authorization: YOUR_API_TOKEN'\ --data '{ "from": "TLkkCeNdJKPNUwucdro84WjswkzM62LCTH", "to": "TUwmZghA7u2GxGxKaxM1mkCmsTF4wHs4vp", "contractaddress": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "amount": 1, "password": "test123"}'import requests
url = "https://api.chaingateway.io/v2/tron/transactions/trc20"payload = { "from": "TLkkCeNdJKPNUwucdro84WjswkzM62LCTH", "to": "TUwmZghA7u2GxGxKaxM1mkCmsTF4wHs4vp", "contractaddress": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "amount": 1, "password": "test123"}headers = { 'Accept': 'application/json', 'content-type': 'application/json', 'Authorization': 'YOUR_API_TOKEN'}
response = requests.post(url, json=payload, headers=headers)print(response.json())const axios = require('axios');
const url = 'https://api.chaingateway.io/v2/tron/transactions/trc20';const payload = { from: 'TLkkCeNdJKPNUwucdro84WjswkzM62LCTH', to: 'TUwmZghA7u2GxGxKaxM1mkCmsTF4wHs4vp', contractaddress: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', amount: 1, password: 'test123'};const headers = { 'Accept': 'application/json', 'content-type': 'application/json', 'Authorization': 'YOUR_API_TOKEN'};
axios.post(url, payload, { headers }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });<?phprequire 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client();$response = $client->post('https://api.chaingateway.io/v2/tron/transactions/trc20', [ 'headers' => [ 'Accept' => 'application/json', 'content-type' => 'application/json', 'Authorization' => 'YOUR_API_TOKEN', ], 'json' => [ 'from' => 'TLkkCeNdJKPNUwucdro84WjswkzM62LCTH', 'to' => 'TUwmZghA7u2GxGxKaxM1mkCmsTF4wHs4vp', 'contractaddress' => 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', 'amount' => 1, 'password' => 'test123' ]]);
echo $response->getBody();?>请求成功时返回交易哈希:
{ "status": 201, "ok": true, "message": "Succesfully created transaction", "data": { "txid": "0x73344d178812d4919e9002c560781f288030edf72ece88823ef1c377dfb71f27" }}有两种错误会以状态码 422 返回,值得分别处理。balance is not sufficient 表示发送地址无力支付这笔交易的资源费用。Validate signature error 表示密钥或密码与 from 地址不匹配。
发送钱包需要 TRX
Section titled “发送钱包需要 TRX”一笔 TRC20 转账是一次智能合约调用,TRON 会为此收取 energy 和 bandwidth 费用。一个只持有代币、没有其他资产的地址无法把代币发送出去。你可以提前为该地址充值 TRX,也可以通过 POST /v2/tron/freeze 和 POST /v2/tron/delegate 质押获取资源,或者让费用由他人代付。费用代付的说明见TRC20 手续费代付。
自己为交易签名
Section titled “自己为交易签名”如果你不想让私钥出现在请求中,可以把转账拆成两次调用。POST /v2/tron/transactions/trc20/build 会返回原始交易的十六进制数据,但不会广播它。你在自己的代码中为这段十六进制数据签名,然后把签名后的交易交给 POST /v2/tron/transactions/broadcast。
curl --request POST\ --url https://api.chaingateway.io/v2/tron/transactions/trc20/build\ --header 'Accept: application/json'\ --header 'content-type: application/json'\ --header 'Authorization: YOUR_API_TOKEN'\ --data '{ "from": "TLkkCeNdJKPNUwucdro84WjswkzM62LCTH", "to": "TUwmZghA7u2GxGxKaxM1mkCmsTF4wHs4vp", "contractaddress": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "amount": 1}'响应中包含 raw_data 和 raw_data_hex。到这一步为止,交易还没有触达网络。
接收关于代币入账的通知
Section titled “接收关于代币入账的通知”如果不想轮询,你可以订阅一个 type 设为 TRC20、并带有代币 contractaddress 的 Webhook,来获知一笔 TRC20 入账。from 和 to 这两个筛选参数可以把范围限定到某一个地址。
curl --request POST\ --url https://api.chaingateway.io/v2/tron/webhooks\ --header 'Accept: application/json'\ --header 'content-type: application/json'\ --header 'Authorization: YOUR_API_TOKEN'\ --data '{ "url": "https://example.com/webhook-receiver", "type": "TRC20", "contractaddress": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "to": "TUwmZghA7u2GxGxKaxM1mkCmsTF4wHs4vp"}'编写接收端代码的方法见创建 Webhook,验证一条通知确实来自 Chaingateway 的方法见Webhook 安全。
服务器未能接受的通知不会自行重新发送。失败的通知会列在 GET /v2/tron/webhooks/notifications/failed 下,可以通过 POST /v2/tron/webhooks/notifications/{id}/retry 重新触发。
在 Nile 测试网上测试
Section titled “在 Nile 测试网上测试”以上所有调用在 TRON Nile 测试网上同样有效。添加请求头 X-Network: testnet,并使用测试代币而不是主网合约。网络列表见支持的网络。