Understand the ERC-20 token smart contract
One of the most significant smart contract standards on Ethereum is known as ERC-20, which has emerged as the technical standard used for all smart contracts on the Ethereum blockchain for fungible token implementations.
ERC-20 defines a common list of rules that all fungible Ethereum tokens should adhere to. Consequently, this token standard empowers developers of all types to accurately predict how new tokens will function within the larger Ethereum system. This simplifies and eases developersβ tasks, because they can proceed with their work, knowing that each and every new project wonβt need to be redone every time a new token is released, as long as the token follows the rules.
Here is, presented as an interface, the functions an ERC-20 must implement. If youβre not sure about what is an interface: check our article about OOP programming in Solidity.
1pragma solidity ^0.6.0;23interface IERC20 {45 function totalSupply() external view returns (uint256);6 function balanceOf(address account) external view returns (uint256);7 function allowance(address owner, address spender) external view returns (uint256);89 function transfer(address recipient, uint256 amount) external returns (bool);10 function approve(address spender, uint256 amount) external returns (bool);11 function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);121314 event Transfer(address indexed from, address indexed to, uint256 value);15 event Approval(address indexed owner, address indexed spender, uint256 value);16}17Show allCopy
Here is a line-by-line explainer of what every function is for. After this weβll present a simple implementation of the a ERC-20 token.
Getters
1function totalSupply() external view returns (uint256);2Copy
Returns the amount of tokens in existence. This function is a getter and does not modify the state of the contract. Keep in mind that there is no floats in Solidity. Therefore most tokens adopt 18 decimals and will return the total supply and other results as followed 1000000000000000000 for 1 token. Not every tokens has 18 decimals and this is something you really need to watch for when dealing with tokens.
1function balanceOf(address account) external view returns (uint256);2Copy
Returns the amount of tokens owned by an address (account
). This function is a getter and does not modify the state of the contract.
1function allowance(address owner, address spender) external view returns (uint256);2Copy
The ERC-20 standard allow an address to give an allowance to another address to be able to retrieve tokens from it. This getter returns the remaining number of tokens that the spender
will be allowed to spend on behalf of owner
. This function is a getter and does not modify the state of the contract and should return 0 by default.
Functions
1function transfer(address recipient, uint256 amount) external returns (bool);2Copy
Moves the amount
of tokens from the function caller address (msg.sender
) to the recipient address. This function emits the Transfer
event defined later. It returns true if the transfer was possible.
1function approve(address spender, uint256 amount) external returns (bool);2Copy
Set the amount of allowance
the spender
is allowed to transfer from the function caller (msg.sender
) balance. This function emits the Approval event. The function returns whether the allowance was successfully set.
1function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);2Copy
Moves the amount
of tokens from sender
to recipient
using the allowance mechanism. amount is then deducted from the callerβs allowance. This function emits the Transfer
event.
Events
1event Transfer(address indexed from, address indexed to, uint256 value);2Copy
This event is emitted when the amount of tokens (value) is sent from the from
address to the to
address.
In the case of minting new tokens, the transfer is usually from
the 0x00..0000 address while in the case of burning tokens the transfer is to
0x00..0000.
1event Approval(address indexed owner, address indexed spender, uint256 value);2Copy
This event is emitted when the amount of tokens (value
) is approved by the owner
to be used by the spender
.
A basic implementation of ERC-20 tokens
Here is the most simple code to base your ERC-20 token from:
1pragma solidity ^0.6.0;23interface IERC20 {45 function totalSupply() external view returns (uint256);6 function balanceOf(address account) external view returns (uint256);7 function allowance(address owner, address spender) external view returns (uint256);89 function transfer(address recipient, uint256 amount) external returns (bool);10 function approve(address spender, uint256 amount) external returns (bool);11 function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);121314 event Transfer(address indexed from, address indexed to, uint256 value);15 event Approval(address indexed owner, address indexed spender, uint256 value);16}171819contract ERC20Basic is IERC20 {2021 string public constant name = "ERC20Basic";22 string public constant symbol = "ERC";23 uint8 public constant decimals = 18;242526 event Approval(address indexed tokenOwner, address indexed spender, uint tokens);27 event Transfer(address indexed from, address indexed to, uint tokens);282930 mapping(address => uint256) balances;3132 mapping(address => mapping (address => uint256)) allowed;3334 uint256 totalSupply_;3536 using SafeMath for uint256;373839 constructor(uint256 total) public {40 totalSupply_ = total;41 balances[msg.sender] = totalSupply_;42 }4344 function totalSupply() public override view returns (uint256) {45 return totalSupply_;46 }4748 function balanceOf(address tokenOwner) public override view returns (uint256) {49 return balances[tokenOwner];50 }5152 function transfer(address receiver, uint256 numTokens) public override returns (bool) {53 require(numTokens <= balances[msg.sender]);54 balances[msg.sender] = balances[msg.sender].sub(numTokens);55 balances[receiver] = balances[receiver].add(numTokens);56 emit Transfer(msg.sender, receiver, numTokens);57 return true;58 }5960 function approve(address delegate, uint256 numTokens) public override returns (bool) {61 allowed[msg.sender][delegate] = numTokens;62 emit Approval(msg.sender, delegate, numTokens);63 return true;64 }6566 function allowance(address owner, address delegate) public override view returns (uint) {67 return allowed[owner][delegate];68 }6970 function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {71 require(numTokens <= balances[owner]);72 require(numTokens <= allowed[owner][msg.sender]);7374 balances[owner] = balances[owner].sub(numTokens);75 allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);76 balances[buyer] = balances[buyer].add(numTokens);77 emit Transfer(owner, buyer, numTokens);78 return true;79 }80}8182library SafeMath {83 function sub(uint256 a, uint256 b) internal pure returns (uint256) {84 assert(b <= a);85 return a - b;86 }8788 function add(uint256 a, uint256 b) internal pure returns (uint256) {89 uint256 c = a + b;90 assert(c >= a);91 return c;92 }93}94Show allCopy
This implementation uses the SafeMath library. Read our tutorial about it if youβd like to learn how the library helps you with handling overflows and underflows in your smart contracts.
Another excellent implementation of the ERC-20 token standard is the OpenZeppelin ERC-20 implementation.