Understanding ABI Files
Last updated
Last updated
Previously you deployed the eosio.token
contract using the provided ABI file. This tutorial will overview how the ABI file correlates to the eosio.token
contract.
ABI files can be generated using the cdt-cpp
utility provided by cdt
. However, there are several situations that may cause ABI's generation to malfunction or fail altogether. Advanced C++ patterns can trip it up and custom types can sometimes cause issues for ABI generation. For this reason, it's imperative you understand how ABI files work, so you can debug and fix if and when necessary.
The Application Binary Interface (ABI) is a JSON-based description on how to convert user actions between their JSON and Binary representations. The ABI also describes how to convert the database state to/from JSON. Once you have described your contract via an ABI then developers and users will be able to interact with your contract seamlessly via JSON.
Start with an empty ABI, name it eosio.token.abi
An ABI enables any client or interface to interpret and even generate a GUI for your contract. For this to work consistently, describe the custom types that are used as a parameter in any public action or struct that needs to be described in the ABI.
The ABI now looks like this:
Structs that are exposed to the ABI also need to be described. By looking at eosio.token.hpp, it can be quickly determined which structs are utilized by public actions. This is particularly important for the next step.
A struct's object definition in JSON looks like the following:
In the eosio.token
contract, there's a number of structs that require definition. Please note, not all of the structs are explicitly defined, some correspond to an actions' parameters. Here's a list of structs that require an ABI description for the eosio.token
contract:
These structs are explicitly defined, as they are a requirement to instantiate a multi-index table. Describing them is no different than defining the implicit structs as demonstrated above.
An action's JSON object definition looks like the following:
Describe the actions of the eosio.token
contract by aggregating all the public functions described in the eosio.token
contract's header file.
Then describe each action's type according to its previously described struct. In most situations, the function name and the struct name will be equal, but are not required to be equal.
Below is a list of actions that link to their source code with example JSON provided for how each action would be described.
Here's a table's JSON object definition:
The eosio.token contract instantiates two tables, accounts and stat.
The accounts
table is an i64 index, based on the account
struct, has a uint64
as it's primary key
Here's how the accounts table would be described in the ABI
The stat
table is an i64 index, based on the currency_stats
struct, has a uint64
as it's primary key
Here's how the stat table would be described in the ABI
You'll notice the above tables have the same "key name." Naming your keys similar names is symbolic in that it can potentially suggest a subjective relationship. As with this implementation, implying that any given value can be used to query different tables.
Finally, an ABI file that accurately describes the eosio.token
contract.
When describing a vector in your ABI file, simply append the type with []
, so if you need to describe a vector of permission levels, you would describe it like so: permission_level[]
It's a rarely used property worth mentioning. You can use base ABI struct property to reference another struct for inheritance, as long as that struct is also described in the same ABI file. Base will do nothing or potentially throw an error if your smart contract logic does not support inheritance.
You can see an example of base in use in the system contract source code and ABI
A few properties of the ABI specification were skipped here for brevity, however, there is a pending ABI specification that will outline every property of the ABI in its entirety.
Ricardian clauses describe the intended outcome of a particular actions. It may also be utilized to establish terms between the sender and the contract.
A generic "future proofing" layer that allows old clients to skip the parsing of "chunks" of extension data. For now, this property is unused. In the future each extension would have its own "chunk" in that vector so that older clients skip it and newer clients that understand how to interpret it.
Every time you change a struct, add a table, add an action or add parameters to an action, use a new type, you will need to remember to update your ABI file. In many cases forgetting to update your ABI file will not produce any error.
Check that your table is accurately described in the ABI file. For example, If you use cleos
to add a table on a contract with a malformed ABI definition and then get rows from that table, you will receive an empty result. cleos
will not produce an error when adding a row nor reading a row when a contract has failed to properly describe its tables in its ABI.
Data Persistence: Learn how data persistence works on VEXANIUM by writing a simple smart contract that functions as an address book.
The following structs are implicit in that a struct was never explicitly defined in the contract. Looking at the action, you'll find two parameters, issuer
of type name
and maximum_supply
of type asset
. For brevity this tutorial won't break down every struct, but applying the same logic, you will end up with the following: