The Ethereum Contract ABI


An application binary interface is an interface between two program modules in computer software, often, between the OS and user programs. An ABI defines how data structures and functions are accessed in machine code; this is often to not be confused with an API, which defines this access in high-level, often human-readable formats as ASCII text files. The ABI is thus the first way of encoding and decoding data into and out of machine language.


In Ethereum, the ABI is employed to encode contracts involving the EVM and to read data out of transactions. The aim of an ABI is to define the functions within the contract which will be invoked and describe how each function will accept arguments and return its result.

A contract’s ABI is stated as a JSON array of function descriptions and events (see Events). A function description may be a JSON object with fields type, name, inputs, outputs, constant, and payable. An occasion description object has fields type, name, inputs, and anonymous.

We use the solc command-line Solidity compiler to supply the ABI for our Faucet.sol example contract:

$ solc –abi Faucet.sol

======= Faucet.sol:Faucet =======

Contract JSON ABI




As we’ll see, the compiler produces a JSON array describing the 2 functions that are defined by Faucet. sol. This JSON is often employed by any application that desires to access the tap contract once it’s deployed. Using the ABI, an application like a wallet or DApp browser can construct transactions that decision the functions in Faucet with the right arguments and argument types. For instance, a wallet would know that to call the function to withdraw it might need to provide a uint256 argument named withdraw amount. The wallet could prompt the user to supply that value, then create a transaction that encodes it and executes the withdraw function.

All that’s needed for an application to interact with a contract is an ABI and therefore the address where the contract has been deployed.

Selecting a Solidity Compiler and Language Version

As we saw within the previous code, our Faucet contract compiles successfully with Solidity version 0.6.4. But what if we had used a special version of the Solidity compiler? The language remains in constant flux and things may change in unexpected ways. Our contract is fairly simple, but what if our program used a feature that was only added in Solidity version 0.6.1 and that we tried to compile it with 0.6.0?

To resolve such issues, Solidity offers a compiler directive referred to as a version pragma that instructs the compiler that the program expects a selected compiler (and language) version. Let’s check out an example:

pragma solidity ^0.6.0;

The Solidity compiler reads the version pragma and can produce a mistake if the compiler version is incompatible with the version pragma. During this case, our version pragma says that this program is often compiled by a Solidity compiler with a minimum version of 0.6.0. The symbol ^ states, however, that we allow compilation with any minor revision above 0.6.0; e.g., 0.6.1, but not 0.7.0 (which may be a major revision, not a minor revision). Pragma directives aren’t compiled into EVM bytecode. They’re only employed by the compiler to see compatibility.

Let’s add a pragma directive to our Faucet contract. We’ll name the new file Faucet2.sol, to stay track of our changes as we proceed through these examples starting in Faucet2.sol: Adding the version pragma to Faucet.

Example 2. Faucet2.sol: Adding the version pragma to Faucet link:code/Solidity/Faucet2.sol[]