Solidity ABIv2: A Foray into the Experimental
RicMoo — March 5, 2018

Today we released v3.0 of ethers.js, a leading library for Ethereum dApps and web3.js alternative. To celebrate the release, this is the first post in a series on using some of the more interesting techniques and features available to Ethereum application.

The ABI (Application Binary Interface) is how a dApp communicates with a Solidity contract; by making function calls, returning data and receiving events. The classic ABI coder does not permit arrays of dynamic types, structs or nested variables between the Solidity contract and the dApp.

This article focuses on a new experimental feature of Solidity, the ABI v2 coder; which allows structs, nested and dynamic variables to be passed into functions, returned from functions and emitted by events.

This example is just a quick demo and should not be considered a production ready (or even production relevant), but is just to get a feel for the potential uses of the ABI v2 coder.

pragma solidity ^0.4.24;
// Enable the ABI v2 Coder
pragma experimental ABIEncoderV2;
contract UserDirectory {
struct Contact {
string email;
string phone;
}
struct User {
string name;
address addr;
Contact contact;
}
address _admin;
mapping (address => User) _users;
// User struct in the event
event UserAdded(address indexed addr, User user);
constructor() {
_admin = msg.sender;
}
// User struct in the method signature
function addUser(User user) public {
require(msg.sender == _admin);
_users[user.addr] = user;
emit UserAdded(user.addr, user);
}
// User struct in the returns
function user(address addr) public view returns (User user) {
return _users[addr];
}
}

Once we have deployed this contract to the Ropsten Test Network we can begin to interact with it, first by adding a user using structured data.

var contract = new ethers.Contract(contractAddress, abi, wallet);
var user = {
name: 'Rick Sanchez',
addr: '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b',
contact: {
email: 'rick.c137@citadel.cfc',
phone: '+1 (555) 314-1593'
}
};
contract.addUser(user).then(function(tx) {
console.log(tx);
});

Once the above transaction is mined, we can use the contract user getter to retrieve the structured data from the contract.

var address = '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b'
contract.user(address).then(function(user) {
console.log(user);
// {
// name: "Rick Sanchez",
// addr: "0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b"
// contact: {
// email: "rick.c137@citadel.cfc",
// phone: "+1 (555) 314-1593",
// }
// }
});

And if we install the onuseradded event listener on the contract, we will get notified whenever any user is added with the structured data.

contract.onuseradded = function(address, user) {
console.log(user);
// {
// name: "Rick Sanchez",
// addr: "0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b"
// contact: {
// email: "rick.c137@citadel.cfc",
// phone: "+1 (555) 314-1593",
// }
// }
};

Please keep in mind this is still considered a highly experimental feature.

In addition to structures and nesting, the ABI v2 coder enables arrays of dynamic objects such as string[] and uint256[][] which were previously not possible.

The ethers.js library aims to provide a single complete and secure library to handle all the functionality you need to safely and easily create Ethereum applications. Some of the extra features include:

  • Connect to the Ethereum blockchain over JSON-RPC, INFURA, Etherscan, Web3 Providers or MetaMask (more back-end services coming soon)
  • Tiny (79kb compressed; 242kb uncompressed)
  • ENS names are first-class citizens; you can use them intead of an address in almost any function that takes an Ethereum address
  • Large suite of test cases (~20,000), both hand-picked and procedurally generated
  • Extensive documentation
  • Fully MIT licensed (including all dependencies)

Thanks for reading, and I hope you found this useful. Please feel free to open any issues for ethers.js on GitHub or follow me on Twitter.