The Application Binary Interface(ABI) allow us to talk to smart contracts on the blockchain or call contract from our Decentralised Applications(dApp).
It was necessary because applications outside the blockchain, or even other smart contracts, needed a way to communicate to contracts deployed to the blockchain. The ABI defines the specific methods, events, and errors that a smart contract has specified in its code.
However, ABI generated by tools like Hardhat/Truffle or by Remix—an IDE that allows you to write smart contracts in your browser, often lives in a JSON RPC file. If you look at this file right now, you will see several lines of code that might take you a while to understand, even though the machine understands.
So, Is it possible to have ABIs in a form that both the EVM and humans—well, developer humans, can understand? Yes, that's where the Human-readable ABI comes into play.
In this guide, you will write a simple, smart contract, compile it using Hardhat, and then generate a Human-readable ABI from the Smart contracts Solidity JSON ABI. First, let's understand what a Human-readable ABI is.
What is a Human-readable ABI?
The Human-readable ABI is a format of the ABI that allows methods, events, and errors in smart contracts to be described using the properties they possess. Properties like name, type, inputs, outputs, etc. These properties are called Solidity Signatures.
It is important to note that a Solidity signature fully describes all the properties the ABI requires and is defined by the following:
name
type (constructor, event, function)
inputs (types, nested structures, and optionally names)
outputs (types nested structures and optionally names)
state mutability (for constructors and methods)
payability (for constructors and methods)
whether inputs are indexed (for events)
Human-readable ABI is a simple format. Machines can parse it. Humans can understand it. This makes it easy to write and use in your code, improving its readability.
If that isn't enticing enough, here's another cool benefit: when human-readable ABI is compared with the standard solidity ABI, it is considerably smaller, and this helps to trim your codebase extra fat.
And that's a good thing, whichever way you think about it.
Prerequisites
Nodejs - You can download the latest version at the Node Js Website.
Hardhat - This tool makes testing, writing, deploying, and debugging smart contracts for DApps easy.
Visual Studio Code (VScode)- An Integrated Development Environment (IDE) that offers features like syntax highlighting and autocompletion for your code. You don't have to install VScode if you already have an IDE installed. This is just my preference.
Basic Javascript Knowledge
Setting up project
To get started, open your terminal in any folder of your choice and run
mkdir human-readable-abi
This will create a new folder inside the folder you used to open the terminal and give it the name human-readable-abi
.
Next, you need to initialize a package.json
file inside your project. To do that, run:
cd human-readable-abi
npm init -y
That will navigate into the human-readable-abi
folder and then initialize a node project. Also, selecting default options for the project.
Now you can install packages you need to write your smart contracts.
You will need Hardhat, so run this command to install Hardhat in your project:
npm install --save-dev hardhat
If you use yarn, run the code below instead
yarn add hardhat
When that is done, if you go to your package.json
File, you should see Hardhat listed as a dependency. Great, let's create a hardhat project and write your smart contract.
Initializing a hardhat project
Initialize a new hardhat project:
npx hardhat
When prompted to choose a project type, Select Create an empty hardhat.config.js
$ npx hardhat
888 888 888 888 888
888 888 888 888 888
888 888 888 888 888
8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888
888 888 "88b 888P" d88" 888 888 "88b "88b 888
888 888 .d888888 888 888 888 888 888 .d888888 888
888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.
888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888
👷 Welcome to Hardhat v2.9.9 👷
? What do you want to do? …
Create a JavaScript project
Create a TypeScript project
❯ Create an empty hardhat.config.js
Quit
Writing smart contract
Start by creating a new directory called contracts and create a file inside the directory called. HelloWorld.sol
.
Paste the code below into the file and take a minute to read the code.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract HelloWorld {
//events
event UpdatedMessages(string oldStr, string newStr);
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
///You cannot do that
error Unauthorized();
// state variable, would be stored permanently on the blockchain
string public message;
address owner;
mapping (uint => address) public ownersList;
uint public ownersCount;
enum dummyEnum {name,age}
// a modifier to prevent function calls
// from unauthorized actors
modifier onlyOwner{
if(msg.sender != owner) revert Unauthorized();
_;
}
// allow the contract to be called with a setup value
// in this case pass initMessage to message(state var)
constructor (string memory initMessage) {
message = initMessage;
owner = msg.sender;
ownersCount = 1;
ownersList[ownersCount] = owner;
}
function update(string memory newMessage) public {
string memory oldMsg = message;
message = newMessage;
emit UpdatedMessages(oldMsg, newMessage);
}
function transferOwnership(address _newOwner) public onlyOwner returns(bool success){
owner = _newOwner;
ownersCount++;
ownersList[ownersCount] = _newOwner;
return true;
}
}
This is a simple smart contract that has a state variable message
, a constructor to initialize the message
when the contract is deployed, and an update
function to modify the message
variable.
An event is also defined that would be emitted whenever the update
function is called. Let's add a few features to the smart contract before we compile it.
The transferOwnership
function would transfer contract ownership to a new address. There is a modifier onlyOwner
that prevents unauthorized calls to transferOwnership
.
ownersList
Mapping keeps a list of the previous and current owners of the smart contract. ownersCount
is an integer that tracks how many owners there are. The dummyEnum
is simply presentational, so it does nothing. We included it to see what the Human-readable ABI format looks like with enums.
error Unauthorized();
It is a custom error that we can use to inform whoever or whatever consumes our contract that they are not permitted to call the transferOwnership
function if they do not own the agreement.
At this stage, we can go ahead and compile your smart contracts.
Compiling Smart Contract
We need to compile our smart contract into a form the EVM can understand. To compile the contract, run npx hardhat compile
it in your terminal. The compile task is one of Hardhat's built-in tasks.
This will compile your code and generate an ABI file for your smart contract. The default location for the ABI JSON is inside the artifacts\contracts\HelloWorld.sol
folder.
Navigate to that folder and open the HelloWorld.json
. It should look like this:
{
"_format": "hh-sol-artifact-1",
"contractName": "HelloWorld",
"sourceName": "contracts/HelloWorld.sol",
"abi": [
{
"inputs": [
{
"internalType": "string",
"name": "initMessage",
"type": "string"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "Unauthorized",
"type": "error"
},
...
// even more lines of JSON code
Awesome! You have just generated an ABI for your smart contract. With this, you can write DAPPs to talk to your smart contract once you deploy it on the blockchain. Let's go ahead and convert that to a human-readable ABI.
Generating Human-readable ABIs
First, I will show you how to generate the Human-readable ABI using a custom generator script then, we will use a simple tool I built, Humanizer, to accomplish the same thing.
Writing a Generator script
Create a new file inside your scripts folder named. ABIconverter.js
.
We would need ethers.js
, a library that helps us interact with the blockchain. Thankfully, Hardhat comes with a copy of ethers.js
out of the box, so we don't need to install it explicitly.
Let's import Hardhat inside ABIconverter.js
const hre = require('hardhat');
Inside the file, you need to import your HelloWorld
JSON ABI. Here's how you will do that:
const helloWorld = require("./artifacts/contracts/HelloWorld.sol/HelloWorld.json");
After the import, here comes the actual conversion part; add the following code to the rest of the code:
const helloWorld = new hre.ethers.utils.Interface(helloWorldJson.abi);
const { full, minimal } = hre.ethers.utils.FormatTypes;
// `full`
const HelloWorld = helloWorld.format(full);
// Replace `full` with `minimal` to reduce the ABI further.
// const HelloWorld = helloWorld.format(minimal);
console.log(HelloWorld);
The new hre.ethers.utils.Interface
will create an interface using the ABI
inside our helloworld
import. helloWorld.format
applies a format to the interface. You can decide between the full
or minimal
format types.
There is a subtle difference between the two formats; you can read it up at the ethers docs
Finally, we log the Human-readable ABI to the console. To test our script, go to your terminal and run
node scripts/ABIconverter.js
You should see your Human-readable ABI printed on your console. It should look like this:
[
'constructor(string initMessage)',
'error Unauthorized()',
'event OwnershipTransferred(address indexed oldOwner, address indexed newOwner)',
'event UpdatedMessages(string oldStr, string newStr)',
'function message() view returns (string)',
'function ownersCount() view returns (uint256)',
'function ownersList(uint256) view returns (address)',
'function transferOwnership(address _newOwner) returns (bool success)',
'function update(string newMessage)'
]
Great Job! You just took an almost unreadable form of ABI and turned it into something you can understand. Even crazier, the EVM can understand too.
With this form, you can see all the functions, events, and other signatures provided by your HelloWorld
smart contract, and to top it all, you can also know the type and name of the argument they need. This is way better than that chunk of hideous ABI you used before, right?
There is another way to generate Human-readable ABI. I dare say it's way easier and could make your workflow faster.
Using the Humanizer tool
Humanizer is a tool that converts JSON ABI to Human-readable ABIs — all in three clicks. Humanizer can compile your ABI whether you compiled it with Hardhat or wrote the code in Remix.
To use Humanizer, follow the steps described below.
Step 1: Open the HelloWorld.json
ABI file. You should find it in ./artifacts/contracts/HelloWorld.sol/HelloWorld.json
Step 2: Copy the contents of the file, i.e., the entire HelloWorld.json
content
Step 3: Open your browser and go to https://kohasummons.github.io/humanizer
Step 4: Paste the JSON you copied inside Humanizer's code editor
Step 5: Select a format type, Full or Minimal
Step 6: Click Generate and then copy the transformed ABI.
That's how simple it is to convert your JSON ABI to Human-readable ABI. You can support Humanizer by giving the project a star on GitHub
How to use the Human-readable ABI
To use the ABI we generated, create a new file called contracts.js
in the root of your app project.
touch contracts.js
Paste the Human-readable ABI code inside contracts.js
. Now all you need to do is import the ABI wherever you need to create a call to the smart contract.
import { HelloWorld } from "./contracts.js"
import { ethers } from "ethers.js"
const { ethereum } = window;
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
// HelloWorld_Contract_Address - Address where contract was deployed to
const HelloWorld = new ethers.Contract(
HelloWorld_Contract_Address,
HelloWorld,
signer
);
console.log(await HelloWorld.ownersCount());
Conclusion
Human-readable ABIs improve your code in two significant ways:
Your code instantly becomes more readable,
You cut out code fat. Two of the most beautiful things you can wish for as a developer.
Now you can go out there and improve your developer experience. Thank you for reading this article. If you found value from it please do like, share and leave a comment.