Contract application binary interface (ABI) is used to encode different types of data while interacting with Ethereum contracts. As a result, both Solidity and modules such as web3.js and ethers.js 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:
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.
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:
The first character, 1, represents the encoding version. Each following character represents the type of an API call parameter.
Note that dynamically-sized types are represented with uppercase letters and statically-sized types are represented with lowercase letters. Another thing to notice is that s represents string32, but this is an artificial type and it is not part of solidity types. This type is instead represented on chain as bytes32. The reasons for this are explained in depth in string32 details section.
The bool type, encoded as character f using the ABI specification schema can be used to encode a boolean value. The header symbol is f, because character b was already reserved for bytes encodings. So we chose letter f as bool values are commonly used to represent "boolean flags".
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).
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.
Strict encoding mode 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.
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 package. Lastly see the file request-utils.ts for example syntax on encoding parameters.