Solidity ERC20 Extensions
ERC20 extensions are extra functions that change supply or add convenience on top of the basic token. Minting creates new units, and burning destroys units that already exist.
Mint creates new units
The owner mints 500 units to a receiver. The supply grows to 1500 and the receiver holds 500.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract MintCoin {
address public owner;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
constructor() {
owner = msg.sender;
totalSupply = 1000;
balanceOf[msg.sender] = 1000;
}
function mint(address to, uint256 amount) public {
require(msg.sender == owner, "only owner mints");
require(to != address(0), "zero receiver");
totalSupply += amount;
balanceOf[to] += amount;
}
function burn(uint256 amount) public {
require(balanceOf[msg.sender] >= amount, "not enough balance");
balanceOf[msg.sender] -= amount;
totalSupply -= amount;
}
}Burn destroys units
Burning 200 units removes them from the caller and from the supply. The supply falls to 800.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract MintCoin {
address public owner;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
constructor() {
owner = msg.sender;
totalSupply = 1000;
balanceOf[msg.sender] = 1000;
}
function mint(address to, uint256 amount) public {
require(msg.sender == owner, "only owner mints");
require(to != address(0), "zero receiver");
totalSupply += amount;
balanceOf[to] += amount;
}
function burn(uint256 amount) public {
require(balanceOf[msg.sender] >= amount, "not enough balance");
balanceOf[msg.sender] -= amount;
totalSupply -= amount;
}
}Only the owner may mint
A mint call from anyone else reverts. A mint call from the owner succeeds.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract MintCoin {
address public owner;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
constructor() {
owner = msg.sender;
totalSupply = 1000;
balanceOf[msg.sender] = 1000;
}
function mint(address to, uint256 amount) public {
require(msg.sender == owner, "only owner mints");
require(to != address(0), "zero receiver");
totalSupply += amount;
balanceOf[to] += amount;
}
function burn(uint256 amount) public {
require(balanceOf[msg.sender] >= amount, "not enough balance");
balanceOf[msg.sender] -= amount;
totalSupply -= amount;
}
}Example
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract CappedCoin {
address public owner;
uint256 public maxSupply = 2000;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
constructor() {
owner = msg.sender;
totalSupply = 1000;
balanceOf[msg.sender] = 1000;
}
function mint(address to, uint256 amount) public {
require(msg.sender == owner, "only owner mints");
require(totalSupply + amount <= maxSupply, "cap reached");
totalSupply += amount;
balanceOf[to] += amount;
}
function burn(uint256 amount) public {
require(balanceOf[msg.sender] >= amount, "not enough balance");
balanceOf[msg.sender] -= amount;
totalSupply -= amount;
}
}Key points
- Mint: creating new units and giving them to an address.
- Burn: destroying units held by the caller.
- Owner-only minting: only the contract owner may create new units.
- Supply cap: a maximum total supply that minting may never pass.
- Permit style: a signature approval lets an owner approve without sending a transaction, and it is described only here because signatures sit outside this course.
In this example, a capped token starts at 1000 units with a cap of 2000. Minting 500 and then burning 200 leaves a supply of 1300, and a further mint of 1000 would pass the cap, so it reverts.
Note
minting and burning change the total supply, so the total supply is not fixed once extensions exist.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Remix IDE
Exercise
What happens to total supply when 200 units are burned?