Solidity Library for Array of Type Address
The AddrArrayLib Library provides utility functions to work with address types
Solidity and Libraries
Because of the immutability of the blockchain, it is extremely important to develop smart contracts with no bugs. Therefore, for the development of Ethereum smart contracts developers should always try to reuse and rely on code that already has been reviewed, tested and used by many developers, for example by using Solidity libraries.
In Solidity, libraries are similar to contracts, they implement the logic of operations and could be deployed once to be used later by a non-limited number of other smart contracts without the need to deploy the same logic again and again. This has the benefit of saving gas for the deployment. However, the fact that multiple contracts depend on the same piece of code could have bad consequences if that piece of code has a vulnerability. So it is very critical and you should be very cautious at choosing the libraries to use in your smart contract. The benefits of libraries are not just limited to reusability, they are also useful to make your code more maintainable, readable and even upgradeable to some degree.
Using Libraries in Solidity
Libraries are like contracts, and we use the library keyword to create them in solidity. However, libraries have no storage, cannot hold any Ether and cannot inherit nor be inherited. There are also two different types of libraries, libraries which have external functions are called linked libraries, they should be deployed first and their addresses should be added to the bytecode of the contract by the deployment process. Libraries which only have internal functions are called embedded libraries. They are deployed with the contract, so their bytecode becomes part of the contract bytecode and is also reachable with jump command. More information about linked and embedded libraries can be found in this article.
A simple example is the following SafeMath Library, which has one function to add two numbers of type uint256 and prevent the possible overflow bug.
To using the library, we first attach the uint256 type to it by using the directive
using SafeMath for uint256
then any variable of type uint256 can call the function add() use a special DELEGATECALL, where the sender and value are not changed and will be just propagated from the parent scope to the child scope, also the storage will still refer to the calling contract.
As we mentioned before libraries have no storage, however they can modify the storage of the linked smart contract by adding the keyword storage to the first argument in the function and using struct to encapsulate the state variable in the library as it is shown in the modified implementation of the SafeMath library. We will use it in the implementation of the address array library.
Why the need for an Array of addresses?
Address is a special data type in Solidity that holds a 20-byte value, and provides built-in functions like transfer and balance. Since every account and smart contract is represented through a unique address, working with addresses is needed in almost every smart contract project.
A simple iterating through a map in solidity is not possible, therefore there are many scenarios where developers must save addresses in an array, especially when it comes to on-chain interactions between contracts where the addresses cannot be given within the transaction data. Recently we worked on a project where we needed to store and manage addresses of investors on-chain in an array. After not finding any existing library for free, public usage, we implemented our own library for managing an array of addresses.
In the above library code, we have the Addresses struct which contains an array of type address and the functions that are usually needed to manage an array such as:
- pushAddress: add an address to the list, only if it does not exist yet. Allowing duplicate addresses is not preferred, because it will make the array bigger, the operations more complicated, and increase the used gas. Therefore, we assume that a simple special treatment for such addresses in the contract code is more efficient.
- removeAddress: remove an address from the list and return true in case the address has been removed. The function will return false if the address does not exist. The method will find the element, swap it with the last element, and then delete it.
- exists: return true if the address exists in the array.
- size: return the size of the array.
- getAddressAtIndex: get the address at the given index.
In all functions, we pass the Addresses argument using the keyword as storage, so the EVM passes it by reference from the storage of the smart contract instead of creating a copy of it in memory.
Now we will create an example contract that uses this library to manage addresses of users, who can mint a Token.
In this contract we used two embedded libraries, the first one is the embedded SafeMath library based on the implementation of Openzeppelin, which provides the logic of addition but does not change the state of the contract directly, and the second library the AddrArrayLib we defined before and imported via its .sol file.
We create a private variable of the struct type AddrArrayLib.Addresses, which represents the state variable of the contract and stores the addresses. After that we have a constructor and three contract functions:
- The addMinter function, which takes in the address of the new minter and calls the trustedMinters.pushAddress function passing in the struct instance from storage.
- The removeMinter function .
- mintToken which checks if the msg.sender exists in the array of trusted minters by calling trustedMinters.exists(msg.sender) and after successful verification mints the token.
The Repository including the library, TokenContract and test instructions can be found on Github under this link.
Summary and Future work
In this article we briefly explained libraries, why are they used and how to use them. Besides, we introduced an implementation of a library to manage addresses in an array, which we consider an often needed building block of smart contracts.
In future work we will focus on testing, improving the current functions and implementing new functions. Furthermore, we will analyze the gas costs and compare a linked version of the library with an embedded one. Finally, after getting the library reviewed by many experienced developers, it will be deployed on the Ethereum blockchain and be available to be used in new projects.
51nodes GmbH based in Stuttgart is a provider of crypto economy solutions.
51nodes supports companies and other organizations in realizing their Blockchain projects. 51nodes offers technical consulting and implementation with a focus on smart contracts, decentralized apps (DApps), integration of Blockchain with industry applications, and tokenization of assets.