Solidity libraries enable blockchain developers to create modular reusable code. This shared usage avoids duplicating code, saves gas during deployment and promotes consistency within a code base.
Let’s create a basic library that demonstrates how this works:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library MyMath {
function add(uint a, uint b) internal pure returns (uint) {
uint c = a + b;
return c;
}
}
contract MyContract {
uint public number;
constructor() {
number = MyMath.add(1,2);
}
}
This code defines a simple smart contract that utilises a library for basic arithmetic operations. The MyMath library includes a function add() that takes two unsigned integers (whole numbers) as inputs and returns their sum.
The function is marked as internal and pure, meaning it can only be called within the contract (or other contracts using this library), and it doesn’t modify or read the blockchain state.
We then define a contract MyContract which has a public state variable called number, which is initialized to the result of adding 1 and 2 using the add function from the MyMath library
In the contract above we have the library and the contract in the same file but more often we would pull the library out to a separate file and import it like this:
import "./MyMath.sol";
This assumes that the library is saved to MyMath.sol which is in the same directory as MyContract.sol
Best Practices & OpenZeppelin
Whilst creating custom libraries can be powerful, it’s crucial to ensure they are secure and well tested. An excellent resource for tried and tested Solidity libraries is OpenZeppelin: https://docs.openzeppelin.com/
OpenZeppelin provides a wide range of Solidity libraries that cover common use cases in smart contract development.
- ERC20.sol – Standard ERC20 token contract, implementing the ERC20 token standard.
- ERC721.sol – Standard contract for non-fungible tokens (NFTs), implementing the ERC721 standard.
- ERC1155.sol – Multi-token standard that can represent both fungible and non-fungible tokens.
- Ownable.sol – Provides basic authorization control by assigning an “owner” to the contract.
- Pausable.sol – Allows for an emergency stop mechanism, useful in case of contract issues.
- AccessControl.sol – A more complex alternative to Ownable, allowing for role-based access control.
- Counters.sol – A utility library for incrementing, decrementing, and resetting counters.
- Governor.sol – Governance system enabling voting and proposals within decentralized organizations.
- UpgradeableProxy.sol – Facilitates the creation of upgradeable smart contracts through proxies.
- ReentrancyGuard.sol – Protects contracts from reentrancy attacks by ensuring non-reentrant function calls.
If you can use an existing OpenZeppelin library then it’s better to do so rather than creating something similar yourself in my opinion as the contracts are widely used and they have a good track record in terms of security. If not these libraries serve as an excellent template for how to structure and document your own custom libraries.