# Solidity ABI

ABI 即应用程序二进制接口，是应用程序与机器码，与底层存储，与执行虚拟机打交道的规范。

## 合约 ABI 定义

{% code title="abi.proto" %}

```
  message ABI {
    message Entry {
      enum EntryType {
        UnknownEntryType = 0;
        Constructor = 1;
        Function = 2;
        Event = 3;
        // Fallback functions are executed whenever a particular contract receives
        // plain Ether without any other data associated with the transaction.
        Fallback = 4;
      }
      message Param {
        // This will cause the respective arguments to be searched for.
        // If arrays (including string and bytes) are used as indexed arguments,
        // the Keccak-256 hash of it is stored as topic instead.
        bool indexed = 1;
        string name = 2;
        string type = 3;
        // SolidityType type = 3;
      }
      enum StateMutabilityType {
        UnknownStateMutabilityType = 0;
        // With pure you cannot access the contract storage.
        // e.g. utility libraries.
        Pure = 1;
        // With view you cannot modify the contract storage, but you can access the storage.
        // e.g. contract getters.
        View = 2;
        Nonpayable = 3;
        Payable = 4;
      }

      // The event was declared as `anonymous`
      bool anonymous = 1;
      // Replaced by view and pure.
      bool constant = 2;
      string name = 3;
      repeated Param inputs = 4;
      repeated Param outputs = 5;
      EntryType type = 6;
      bool payable = 7;
      StateMutabilityType state_mutability = 8;
    }
    // renamed: entrys
    repeated Entry entries = 1;
  }
```

{% endcode %}

如上定义。

## 合约调用 ABI

合约调用传参，采用 `byte4(keccak256(函数签名)) + 函数参数列表 ABI encode`.

例如 TRC20 转账, 给地址 `TJRabPrwbZy45sbavfcjinPJC18kjpRv8` 转账 `100000` 单位:

```
function transfer(address _to, uint256 _amount) returns (bool)
    => keccak256("transfer(address,uint256)")[:4].hex()
    => a9059cbb

base58.b58decode_check('TJRabPrwbZy45sbavfcjinPJC18kjpRTv8').hex()
    => '415cbdd86a2fa8dc4bddd8a8f69dba48572eec07fb'
    => 截取后20字节 5cbdd86a2fa8dc4bddd8a8f69dba48572eec07fb

hex(100000) => 0x186a0

则得到调用 data:

a9059cbb => the function signature
0000000000000000000000005cbdd86a2fa8dc4bddd8a8f69dba48572eec07fb => 地址 TJRabPrwbZy45sbavfcjinPJC18kjpRv8
00000000000000000000000000000000000000000000000000000000000186a0 => uint 100000
```

参考: 函数 selector 数据库 <https://www.4byte.directory/>

## 合约返回 ABI

合约函数的返回值，按 returns 类型列表执行 ABI encode.

## 合约事件 ABI

参考 TVM 一节中对 Event 的处理描述。

## TRON 地址的特殊处理

由于 EVM 中 address 为 20 字节 bytes160 类型，而 TRON 地址的 hex 地址为 21 字节， 所以在传入参数的时候需要截取后 20 字节。

同时，在编写合约中，地址字面常量要求使用 Checksum Address 格式， 此时 20 字节地址还需要根据 checksum 要求变更大小写。(以编译报错信息为准)

TVM 对 21 字节地址只有有限的支持，建议不要依赖此特性。

## ABIEncoderV2

ABIEncoderV2 为 Solidity 智能合约提供了结构体作为函数参数和结构体作为函数返回值的支持。

\[tronpy]\(<https://tronpy.readthedocs.io/en/latest/contract.html#contract-with-un-published-abi>) 支持对 ABIEncoderV2 的智能合约调用。

{% hint style="info" %}
由于 java-tron 的 protobuf 结构定义缺陷, java-tron 不支持保存 ABIEncoderV2 的 ABI. 所以调用合约需要开发者自己提供 ABI JSON 文件。
{% endhint %}
