地址与数据编码

说明 TRON API 中地址、交易数据和智能合约参数的编码方式,涵盖 Base58、Hex、visible 标志、ABI 编码,以及 raw_data 与 raw_data_hex 的区别。

接入 TRON API 时,最常见的编码问题集中在两处:

  • 地址格式:支持 Base58Check(以 T 开头)与 Hex(以 41 开头)两种相互等价的格式,并由 visible 参数标志控制切换。
  • 交易体格式:构建交易时,接口会同时返回结构化的 JSON 对象(raw_data)与其经过 Protobuf 序列化后的十六进制形式(raw_data_hex)。

任一环节编码错误,都可能导致签名校验失败或 CONTRACT_VALIDATE_ERROR。下面按地址、交易数据和合约参数三类场景说明。

📘

前置阅读


地址格式

TRON 地址在日常开发和链上数据交互中以两种可互换的格式存在:

格式示例长度典型适用场景
Base58CheckTPL66VK2gCXNCD7EJg9pgJRfqcRazjhUZY34 个字符,以 T 开头直接面向用户(如钱包 UI、区块浏览器、文档说明)
Hex41928c9af0651632157ef27a2cf17ca72c575a4d2142 个字符,在主网上以 41 开头底层协议与数据传输(如 Protobuf 结构、默认 API 请求)

这两种格式在底层均编码了相同的 21 字节地址:包括 1 字节的网络前缀(当前所有活跃的 TRON 网络——包括主网 Mainnet、Shasta 测试网和 Nile 测试网,其前缀均为 0x41),以及由公钥派生出的 20 字节哈希值。详细的派生算法请参阅账户管理

📘

说明

在旧版文档或配置文件(如 framework/src/main/resources/config.conf)中可能出现的 0xa0 前缀是早期测试网遗留的配置选项(与当前的 Nile、Shasta 或本地私有网络配置无关)。目前所有活跃的 TRON 网络均不采用 0xa0 前缀。

visible 参数标志

大部分 TRON 节点 API 都支持在请求中传入 visible 字段。该参数用于控制请求和响应数据载荷(Payload)中的地址编码格式:

visible请求与响应中的地址格式
false(默认)十六进制 Hex 格式(以 41 开头)
trueBase58Check 格式(以 T 开头)

示例如下:

POST /wallet/createtransaction
Content-Type: application/json

{
  "visible": true,
  "owner_address": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
  "to_address": "TPL66VK2gCXNCD7EJg9pgJRfqcRazjhUZY",
  "amount": 1000000
}
⚠️

注意

请保持地址格式与 visible 标志一致。如果 visible 设为 false(或省略该字段)却传入 Base58 地址,节点会返回参数校验错误。反之,如果 visibletrue 时传入 Hex 地址,同样会被拒绝。

某些 API 要求将 visible 作为 URL 查询字符串传入(例如 ?visible=true),而不是写入 JSON 请求体。调用前请确认对应接口的参数说明。

格式转换方法

主流 TRON SDK 都提供地址转换工具函数,通常不需要手动实现底层算法。

SDKBase58 转换为 HexHex 转换为 Base58
TronWeb (JavaScript)tronWeb.address.toHex(b58)tronWeb.address.fromHex(hex)
Trident (Java)KeyPair.toBase58CheckAddress(hexBytes)(使用 Numeric.hexStringToByteArray(hex) 得到字节数组后再进行反向操作)
gotron-sdk (Go)common.DecodeCheck(b58)common.EncodeCheck(hexBytes)

如果确实需要手动转换地址格式,算法步骤如下:

  • Hex 转换为 Base58Check:若地址缺少前缀,先在头部补齐 0x41 网络前缀字节。对得到的 21 字节地址执行两次连续的 SHA-256 计算。取第二次 SHA-256 计算结果的前 4 个字节作为校验和附加到该 21 字节地址的尾部。最后,对合并后的 25 字节数据进行 Base58 编码。
  • Base58Check 转换为 Hex:对 34 字符的 Base58Check 编码字符串进行 Base58 解码,得到 25 字节的数据。验证最后的 4 字节校验和是否正确。如果正确,剔除校验和,取前 21 字节即为带有网络前缀的 Hex 格式地址。
⚠️

重要

在 Hex 格式下,0x41 网络前缀是强制要求的。忽略该前缀会导致地址长度缩短至 20 字节,此类地址将被所有 TRON API 接口直接拒绝。


交易数据载荷:raw_dataraw_data_hex

调用构建交易的 API 时,返回的交易信息会同时包含两种数据载荷:

  • raw_data:一个结构化的 JSON 对象,包含了交易合同、TAPOS 引用区块数据、过期时间戳以及创建时间戳等明细。
  • raw_data_hexraw_data 结构经 Protobuf 序列化并进行十六进制(Hex)编码后的原始数据字符串。

在密码学签名时,签名的计算对象是 SHA-256(raw_data_bytes)(其中 raw_data_bytes 代表 Protobuf 序列化后的字节数组)。在实际开发中,SDK 会自动解析 raw_data 或者直接从 raw_data_hex 获取原始字节完成签名。这两种路径在底层产生的签名哈希完全一致。

⚠️

注意

在构建交易与执行签名之间,绝对不要尝试手动修改 raw_data 中的数据或重新对 JSON 字段进行排序。任何微小的变化都会直接导致计算出的 txID 发生改变,从而引发节点拒绝接收和广播该交易。


智能合约参数 ABI 编码

发起合约交互请求时(调用 /wallet/triggersmartcontract/wallet/triggerconstantcontract),需要提供 parameter 字段。该字段是被调用函数入参的 ABI 序列化编码。TRON 采用与以太坊一致的 ABI 编码规范,但地址格式有一个关键差异。

编码规则

  • 函数选择器(Function Selector):取函数签名的 Keccak-256 哈希值的前 4 个字节。函数签名指“函数名(以逗号分隔的参数类型)”,不能包含空格。例如:transfer(address,uint256) 对应的函数选择器为 0xa9059cbb
  • 参数编码:每个参数值必须对齐并填充到 32 字节(256 位):
    • uint256 等整数:转换为大端序的 32 字节整数。
    • address 账户地址:必须去掉 0x41 网络前缀,保留其余 20 字节,并在左侧填充零至 32 字节。
    • stringbytes 等动态类型:使用包含数据长度前缀的动态编码规则(参见 Solidity ABI 标准规范说明)。
⚠️

警告

在 ABI 编码中,必须移除地址头部的 0x41 前缀字节!
TRON 的虚拟机在处理合约中的地址参数时,使用的是 20 字节的原始地址(与以太坊格式对齐)并左侧补零填充至 32 字节——而非 21 字节的带有网络前缀的主网格式。传入带 0x41 的 21 字节地址(强行补零填充至 32 字节)是开发中最常见的合约调用报错原因。

示例:TRC-20 Token 转账

以在 TRC-20 Token 合约上调用 transfer(address,uint256),向地址 TXT7aiRQCLiMgsMZgFceLYbQu3MynssYUK 转账 100 个 Token 为例。假设该 Token 精度为 6,则 100 Token 对应 100,000,000 个最小单位,即 Hex 格式 0x5f5e100

  1. 计算函数选择器transfer(address,uint256) 的选择器为 a9059cbb
  2. 转换并对齐接收地址TXT7aiRQCLiMgsMZgFceLYbQu3MynssYUK 的 21 字节 Hex 地址为 41eba1c3a4a5e7a26acab1e10cd6e6c6e2db6ee9c2。剔除头部的 41 后为 eba1c3a4a5e7a26acab1e10cd6e6c6e2db6ee9c2。左侧补零对齐 32 字节后为 000000000000000000000000eba1c3a4a5e7a26acab1e10cd6e6c6e2db6ee9c2
  3. 转换并对齐转账金额100000000(即十进制 100,000,000)转换为十六进制为 5f5e100。右对齐、左侧补零至 32 字节后为 0000000000000000000000000000000000000000000000000000000005f5e100

将上述三段十六进制字符串无缝拼接,即可获得 triggersmartcontract 接口请求中 parameter 所需的最终编码值:

a9059cbb000000000000000000000000eba1c3a4a5e7a26acab1e10cd6e6c6e2db6ee9c20000000000000000000000000000000000000000000000000000000005f5e100
💡

提示

主流 SDK 的高级封装方法(如 TronWeb 中的 tronWeb.transactionBuilder.triggerSmartContract(...))通常会自动处理 ABI 编码。只有跳过 SDK、直接通过原始 HTTP 客户端调用节点接口,或目标合约没有公开 ABI 数据时,才需要手动执行上述编码步骤。


TRC-10 Token 的唯一性标识

与 TRC-20 Token 不同,TRC-10 资产是通过一个全局唯一的数字 Token ID 进行识别的,而不是通过智能合约地址。但在一些历史 API 接口的交易返回中,表示资产名称的 asset_name 字段的实际数据类型取决于交易打包入账时的区块高度:

打包区块范围asset_name 字段的实际内容示例数据
区块 5537806 及之后(当前绝大部分区块)全局唯一的数字 Token ID"1002000"
区块 5537806 之前(2019 年初及更早的历史区间)资产的文本名称字符串"USDJ"

这一变化源于早期协议演进:起初 TRON 要求每个 TRC-10 Token 注册名称保持唯一,因此可以直接将名称作为标识符。随着 14 号治理提议 激活,系统取消了命名唯一性限制,数字 ID 成为 TRC-10 资产的唯一标识符。

📘

说明

新建集成系统通常只需将 asset_name 视为数字形式的 Token ID,并过滤或拒绝区块 5537806 之前的历史转账。如果需要同步 TRON 全网完整历史数据(例如构建区块浏览器或历史索引服务),必须按区块高度做分支解析。


常见编码错误总结

  • 在构建与签名交易时,visible 标志配置不一致:构建交易的 API 响应结果与后续执行签名并广播的 Payload 中必须使用相同的 visible 状态。虽然各 SDK 会在内部自动调和,但如果直接使用原始 HTTP 接口,请确保该参数始终一致。
  • 在 ABI 编码的地址参数中遗留了 0x41 前缀:ABI 规范强制使用 20 字节的原始哈希。如果在 ABI 编码中包含了 0x41,将产生越界的 21 字节数据,导致智能合约无法正常解析并报错。
  • 在未启用 visible 参数时在 API 中传入 Base58 地址:默认情况下,节点会将输入视为十六进制。如果传入类似 T... 的地址,接口会报错返回 INVALID_PARAMETER。此时需要显式设置 visible: true 或进行地址格式转换。
  • raw_data_hex 按照字符串类型而非二进制字节数组进行签名哈希计算:交易签名是在 Protobuf 序列化后的原始二进制字节上执行的,而非对代表十六进制的 ASCII 字符串本身做哈希。使用封装好的 SDK 签名接口可完美规避此问题。
  • 在签名计算前对 raw_data 字段的字段顺序进行重排:哪怕仅仅更改了 JSON 中字段的键值对排布顺序,也会直接更改哈希计算输入,导致算出的 txID 发生变动并致使签名作废。在获取节点返回明文后,请原样传递或直接对十六进制的 raw_data_hex 进行哈希操作。
  • 依赖 TRC-10 Token 的文本名称作为唯一身份主键:在 TRON 网络中,随着 14 号治理提议激活,多个 TRC-10 资产可以共享相同的名称。生产代码中必须仅使用数字形式的 ID(如 1002000)来关联与存储 TRC-10 资产信息。

相关资源