# Airnode ABI Specification
Contract application binary interface (ABI) (opens new window) is used to encode different types of data while interacting with Ethereum contracts. As a result, both Solidity and modules such as web3.js (opens new window) and ethers.js (opens new window) treat ABI encodingâdecoding functionality as a first-class citizen. This makes using contract ABI for encoding API call parameters a very attractive option.
Although encoding API call parameters using contract ABI has many advantages, it cannot be used for this purpose directly. Quoting from the Solidity docs (opens new window):
The encoding is not self describing and thus requires a schema in order to decode.
This means that when passing API call parameters (of type bytes
), you would
also need to pass a list of the types for these parameters, which is cumbersome
and it is not clear how these types would be encoded. As a solution, Airnode
uses Airnode ABI specifications, an extension of contract ABI specifications
that includes a header that keeps the schema.
# Header
The Airnode ABI specifications header is of type bytes32
and acts as the
schema (i.e., describes the types of the API call parameters). The header is
encoded in UTF-8 for ease of use. Here is an example:
"1BSabiuBa"
The first character, 1
, represents the encoding version. Each following
character represents the type of an API call parameter.
# Type encodings
The types are encoded in UTF-8 characters as follows:
B: bytes
S: string
a: address
u: uint256
i: int256
b: bytes32
2
3
4
5
6
Note that dynamically-sized types are represented with uppercase letters, and statically-sized types are represented with lowercase letters.
# Encoding format
Airnode ABI specifications has the following encoding format (which is somewhat similar to SDS (opens new window)):
[------------------------][-----------------------------------------]
Header of type bytes32 API call parameter nameâvalue pairs
2
Note that each API call parameter is preceded with a name of type bytes32
.
# Example encoding
To encode the following API call parameters
{
"MyFirstBytes": "0x1234",
"MyString": "1234",
"MyFirstAddress": "0x0000000000000000000000000000000000001234",
"MyBytes32": "1234",
"MyInt256": "-1234",
"MyUint256": "1234",
"MySecondBytes": "0x5678",
"MySecondAddress": "0x0000000000000000000000000000000000005678"
}
2
3
4
5
6
7
8
9
10
you would do this in a requester contract as:
bytes memory parameters = abi.encode(
bytes32("1BSabiuBa"),
bytes32("MyFirstBytes"), bytes(hex"1234"),
bytes32("MyString"), "1234",
bytes32("MyFirstAddress"), 0x0000000000000000000000000000000000001234,
bytes32("MyBytes32"), bytes32("1234"),
bytes32("MyInt256"), -1234,
bytes32("MyUint256"), 1234,
bytes32("MySecondBytes"), bytes(hex"5678"),
bytes32("MySecondAddress"), 0x0000000000000000000000000000000000005678
);
2
3
4
5
6
7
8
9
10
11
Note that you do not need to add an external library to the contract, and
abi.encode()
is fairly cheap in terms of gas usage (compared to alternative
encoding methods).
# Example decoding
If you know the schema of the encoded parameters, then decode them on-chain. For
example, if the schema is (bytes,string)
:
(
bytes32 header,
bytes32 name1, bytes memory value1,
bytes32 name2, string memory value2
) = abi.decode(parameters, (bytes32,bytes32,bytes,bytes32,string));
2
3
4
5
Note that this disregards the header and hard codes the schema into the code. It is also possible to parse the header on-chain and decode accordingly, yet that would be a lot more complex.
# Details
# bytes32
A parameter being of type bytes32
implies that the parameter is UTF-8 encoded
text. For example, if the parameter is
0x68656c6c6f000000000000000000000000000000000000000000000000000000
Airnode will decode it as
"hello"
and feed that to the API, which is what the user would want to do in most cases.
This becomes a problem if the parameter is not encoded text, but for example a hash such as:
0x1fd36c61981313c0c155d33ffac0325bd7c00d21d52442981bb13d2fa13e8f71
If this hash is encoded as a bytes32
type, Airnode will decode it as:
ĂlaÂĂĂUĂ?ĂșĂ2[ĂĂ
!Ă$B±=/ÂĄ>Âq
2
which is probably not what the user is looking for. Instead, the user should
typecast the parameter into a bytes
type as:
bytes parameterAsBytes = abi.encodePacked(parameterAsBytes32);
and encode it as such. Then, Airnode would decode it as
"0x1fd36c61981313c0c155d33ffac0325bd7c00d21d52442981bb13d2fa13e8f71"
# Omitted types
array
and tuple
are omitted because they are not suitable to be used as API
parameters. uint8-uint128
, int8-int128
, bytes1-bytes31
are omitted because
they are padded to 32 bytes by the ABI encoder anyway (meaning that the user
should simply typecast these to the 32-byte versions).
Finally, bool
is omitted to avoid confusion because there are too many types
that start with the letter 'B'. A simple workaround is to encode a bool
type
parameter as bytes32
as:
bytes32 boolAsBytes32 = boolAsBool ? bytes32("true") : bytes32("false");
This works because both bool(true)
and bytes32("true")
would be decoded as
"true"
by the Airnode, and vice versa.
# Size limit
The header can encode up to 31 parameters (and 1 byte is used to encode the encoding version). This is far more than what would be needed in practice, and thus is tolerated to avoid a more complex solution.
# Padding
Strict encoding mode (opens new window) is used so that you can decode the values later on. This means that each parameter will be padded with zeros to complete them to 32 bytes. Although this padding increases gas costs, ABI encoding/decoding functions being cheap balances this. Furthermore, the template pattern used in the protocols allows for the referencing of these encoded parameters without explicitly passing them in requests, making the increased cost induced by padding irrelevant in most cases.
# @api3/airnode-abi
Encode and decode parameters with the airnode-abi package.
import { encode } from '@api3/airnode-abi';
import { decode } from '@api3/airnode-abi';
const parameters = [
{ type: 'bytes32', name: 'from', value: 'ETH' },
{ type: 'uint256', name: 'amount', value: '100000' },
];
const encodedData = encode(parameters);
const decoded = decode(encodedData);
console.log('ENCODED:', encodedData);
console.log('\nDECODED:', decoded);
2
3
4
5
6
7
8
9
10
11
12
See the package doc airnode-abi for more information on how to encode and decode with Airnode ABI off-chain. Also see code samples in the examples (opens new window) package.