Always use OpenZeppelin
Don’t get me wrong, writing smart contracts from scratch is a great learning tool. Tasking yourself with creating an ERC20-compliant contract from start to finish is one of the best ways to gain an understanding of the logic behind it.
However, for production applications, don’t reinvent the wheel.
Libraries like OpenZeppelin are scrutinized by the Ethereum development community at large. They’re continuously being updated and reviewed. They’re also publically accessible and easy to use. It doesn’t make sense to create your own when libraries like this exist.
Importing OpenZeppelin
To install OpenZeppelin into your project, run the following command:
npm install @openzeppelin/contracts --save
This will download all smart contracts into node_modules/
.
Once installed, you can import smart contracts into your own. This is an example of importing the OpenZeppelin ERC20
token contract in a smart contract:
pragma solidity ^0.5.5;
import "@openzeppelin/contracts/token/ERC20/ERC720.sol";
contract MyContract is ERC20 { ...
Here are some useful Token, Math, Utils, and Ownable contracts from OpenZeppelin you can easily implement in your projects.
Tokens
ERC20
There are six publically available functions that ERC20
contracts need to implement, as well as two events. By importing OpenZeppelin’s ERC20
contract, you don’t need to implement any of these yourself.
pragma solidity ^0.5.5;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
contract MyERC20 is ERC20, ERC20Detailed {
constructor(string memory _name, string memory _symbol, uint8 _decimals) public ERC20Detailed(_name, _symbol, _decimals) {
}
}
ERC20Detailed
is used to initialize the name, symbol, and decimals for the token, but they aren’t necessary if your project doesn’t require a named ERC20
token.
ERC721
Since ERC721
tokens are unique, a struct and an array of structs are commonly used to store them.
pragma solidity ^0.5.5;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract MyERC721 is ERC721 {
struct Person {
string name;
uint8 age;
uint8 height;
}
Person[] public people;
function newPerson(string memory _name, uint8 _age, uint8 _height, address _to) public returns (uint)
{
uint id = people.length;
people.push(Person(_name, _age, _height));
_safeMint(_to, id);
return id;
}
}
Instead of implementing all nine functions and three events, this contract inherits those and exposes the ability to create new Person
tokens.
Math
SafeMath
In most modern programming languages, safety in arithmetic operations is accounted for, so little thought goes into their implementation. However, in Solidity, overflows and underflows present a security risk.
SafeMath
is a library that ensures safe arithmetic operations by reverting the transaction if the bounds of an integer data type are exceeded.
pragma solidity ^0.5.5;
import "@openzeppelin/contracts/math/SafeMath.sol";
contract BasicSafeMath {
using SafeMath for uint;
function doSomeMath(uint _a, uint _b) public returns (uint) {
return _a.sub(_b);
}
}
The using
statement indicates to the compiler that the contract is using functions defined in SafeMath
for uint
operations. Instead of using arithmetic operators (+
, -
, *
, /
, %
), use the functions add()
, sub()
, mul()
, div()
, and mod()
.
Utils
SafeCast
Casting uint
variables for an integer of a smaller size may present an overflow risk. Use SafeCast
to cast larger integer data types to smaller ones (i.e. uint256
to uint8
).
This can be used in tandem with SafeMath
, which performs the arithmetic operations on uint256
only.
pragma solidity ^0.5.5;
import "@openzeppelin/contracts/math/SafeCast.sol";
contract BasicSafeCast {
using SafeCast for uint;
function castToUint8(uint _a) public returns (uint8) {
return _a.toUint8();
}
}
Ownership
Ownable
Access to certain functions in a smart contract sometimes needs to be restricted so that only the owner of the contract can successfully invoke them. A common pattern is to use the onlyOwner
modifier in function definitions. Instead of coding this pattern yourself, OpenZeppelin’s Ownable
contract does this for you.
pragma solidity ^0.5.5;
import "@openzeppelin/contracts/ownership/Ownable.sol";
contract OwnableContract is Ownable {
function restrictedFunction() public onlyOwner returns (uint) {
return 99;
}
function openFunction() public returns (uint) {
return 1;
}
}
Conclusion
Always use libraries for the most basic implementations of coding standards. At this point, the best in the industry is OpenZeppelin. It’s safer, quicker, cleaner, and easier than reinventing the wheel yourself.
Learn More
If you’re interested in Blockchain Development, I write tutorials, walkthroughs, hints, and tips on how to get started and build a portfolio. Check out this evolving list of Blockchain Development Resources.
If you enjoyed this post and want to learn more about Smart Contract Security, Blockchain Development or the Blockchain Space in general, I highly recommend signing up to the Blockgeeks platform. They have courses on a wide range of topics in the industry, from Coding to Marketing to Trading. It has proven to be an invaluable tool for my development in the Blockchain space.