Squashed commit of the following:
commit fcf35eb806100de300bd9803ce3150dde1ecc424
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 17 17:16:04 2019 -0300
remove all docsite dependency
commit eeaee9a9d43d70704f6ab17b5126ddbd52b93a50
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 17 17:15:23 2019 -0300
update solidity-docgen
commit f021ff951829ea0c155186749819403c6b76e803
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 17 17:05:06 2019 -0300
update docsite script for new setup
commit ff887699d381cfbbe3acf1f1c0de8e22b58480f3
Merge: c938aa1d 84f85a41
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 17 16:46:46 2019 -0300
Merge branch 'master' into antora
commit c938aa1d9ed05ac83a34e2cebd8353f8331ad6d6
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Tue Jul 16 18:24:29 2019 -0300
make component name shorter
commit 5bbd6931e02cbbd8864c82655ad0f390ceead5f3
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 10 20:16:17 2019 -0300
add all info to docs templates
commit 39682c4515d7cf0f0368ed557f50d2709174208a
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 10 20:13:49 2019 -0300
fix npm docsite script
commit 7ae46bd4a0437abf66150d54d05adf46e3de2cab
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 10 18:48:05 2019 -0300
convert inline docs to asciidoc
commit cfdfd3dee4b4bf582fde22c8cb6e17a603d6e0c8
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 10 17:34:52 2019 -0300
add missing contract names in readmes
commit 15b6a2f9bfb546cf1d3bf4f104278b118bf1b3f4
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 10 17:16:47 2019 -0300
fix script path
commit 80d82b909f9460d1450d401f00b3f309da506b29
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 10 17:13:53 2019 -0300
update version of solidity-docgen
commit a870b6c607b9c2d0012f8a60a4ed1a1c8b7e8ebd
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 10 17:03:53 2019 -0300
add nav generation of api ref
commit 069cff4a25b83752650b54b86d85608c2f547e5e
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Wed Jul 10 16:32:14 2019 -0300
initial migration to asciidoc and new docgen version
commit 55216eed0a6551da913c8d1da4b2a0d0d3faa1a8
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Tue Jun 25 20:39:35 2019 -0300
add basic api doc example
commit 0cbe50ce2173b6d1d9a698329d91220f58822a53
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Tue Jun 25 19:31:31 2019 -0300
add sidebars
commit 256fc942845307258ac9dc25aace48117fa10f79
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Tue Jun 25 15:22:38 2019 -0300
add page titles
commit f4d0effa70e1fc0662729863e8ee72a8821bc458
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Tue Jun 25 15:19:41 2019 -0300
add contracts index file
commit b73b06359979f7d933df7f2b283c50cb1c31b2a0
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Tue Jun 25 15:14:52 2019 -0300
fix header levels
commit fb57d9b820f09a1b7c04eed1a205be0e45866cac
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Tue Jun 25 15:11:47 2019 -0300
switch format to preferred asciidoctor format
commit 032181d8804137332c71534753929d080a31a71f
Author: Francisco Giordano <frangio.1@gmail.com>
Date: Tue Jun 25 15:05:38 2019 -0300
initialize antora component and convert docs to asciidoc
110 lines
6.0 KiB
Plaintext
110 lines
6.0 KiB
Plaintext
= Creating ERC20 Supply
|
|
|
|
In this guide you will learn how to create an ERC20 token with a custom supply mechanism. We will showcase two idiomatic ways to use OpenZeppelin for this purpose that you will be able to apply to your smart contract development practice.
|
|
|
|
'''''
|
|
|
|
The standard interface implemented by tokens built on Ethereum is called ERC20, and OpenZeppelin includes a widely used implementation of it: the aptly named https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.1.2/contracts/token/ERC20/ERC20.sol[`ERC20`] contract. This contract, like the standard itself, is quite simple and bare-bones. In fact, if you try deploy an instance of `ERC20` as-is it will be quite literally useless... it will have no supply! What use is a token with no supply?
|
|
|
|
The way that supply is created is not defined in the ERC20 document. Every token is free to experiment with their own mechanisms, ranging from the most decentralized to the most centralized, from the most naive to the most researched, and more.
|
|
|
|
[[fixed-supply]]
|
|
== Fixed supply
|
|
|
|
Let's say we want a token with a fixed supply of 1000, initially allocated to the account that deploys the contract. If you've used OpenZeppelin v1, you may have written code like the following.
|
|
|
|
[source,solidity]
|
|
----
|
|
contract ERC20FixedSupply is ERC20 {
|
|
constructor() public {
|
|
totalSupply += 1000;
|
|
balances[msg.sender] += 1000;
|
|
}
|
|
}
|
|
----
|
|
|
|
Starting with OpenZeppelin v2 this pattern is not only discouraged, but disallowed. The variables `totalSupply` and `balances` are now private implementation details of `ERC20`, and you can't directly write to them. Instead, there is an internal `_mint` function that will do exactly this.
|
|
|
|
[source,solidity]
|
|
----
|
|
contract ERC20FixedSupply is ERC20 {
|
|
constructor() public {
|
|
_mint(msg.sender, 1000);
|
|
}
|
|
}
|
|
----
|
|
|
|
Encapsulating state like this makes it safer to extend contracts. For instance, in the first example we had to manually keep the `totalSupply` in sync with the modified balances, which is easy to forget. In fact, I omitted something else that is also easily forgotten: the `Transfer` event that is required by the standard, and which is relied on by some clients. The second example does not have this bug, because the internal `_mint` function takes care of it.
|
|
|
|
[[rewarding-miners]]
|
|
== Rewarding miners
|
|
|
|
The internal `_mint` function is the key building block that allows us to write ERC20 extensions that implement a supply mechanism.
|
|
|
|
The mechanism we will implement is a token reward for the miners that produce Ethereum blocks. In Solidity we can access the address of the current block's miner in the global variable `block.coinbase`. We will mint a token reward to this address whenever someone calls the function `mintMinerReward()` on our token. The mechanism may sound silly, but you never know what kind of dynamic this might result in, and it's worth analyzing and experimenting with!
|
|
|
|
[source,solidity]
|
|
----
|
|
contract ERC20WithMinerReward is ERC20 {
|
|
function mintMinerReward() public {
|
|
_mint(block.coinbase, 1000);
|
|
}
|
|
}
|
|
----
|
|
|
|
As we can see, `_mint` makes it super easy to do this correctly.
|
|
|
|
[[modularizing-the-mechanism]]
|
|
== Modularizing the mechanism
|
|
|
|
There is one supply mechanism already included in OpenZeppelin: https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.1.2/contracts/token/ERC20/ERC20Mintable.sol[`ERC20Mintable`]. This is a generic mechanism in which a set of accounts is assigned the `minter` role, granting them the permission to call a `mint` function, an external version of `_mint`.
|
|
|
|
This can be used for centralized minting, where an externally owned account (i.e. someone with a pair of cryptographic keys) decides how much supply to create and to whom. There are very legitimate use cases for this mechanism, such as https://medium.com/reserve-currency/why-another-stablecoin-866f774afede#3aea[traditional asset-backed stablecoins].
|
|
|
|
The accounts with the minter role don't need to be externally owned, though, and can just as well be smart contracts that implement a trustless mechanism. We can in fact implement the same behavior as the previous section.
|
|
|
|
[source,solidity]
|
|
----
|
|
contract MinerRewardMinter {
|
|
ERC20Mintable _token;
|
|
|
|
constructor(ERC20Mintable token) public {
|
|
_token = token;
|
|
}
|
|
|
|
function mintMinerReward() public {
|
|
_token.mint(block.coinbase, 1000);
|
|
}
|
|
}
|
|
----
|
|
|
|
This contract, when initialized with an `ERC20Mintable` instance, will result in exactly the same behavior implemented in the previous section. What is interesting about using `ERC20Mintable` is that we can easily combine multiple supply mechanisms by assigning the role to multiple contracts, and moreover that we can do this dynamically.
|
|
|
|
[[automating-the-reward]]
|
|
== Automating the reward
|
|
|
|
Additionally to `_mint`, `ERC20` provides other internal functions that can be used or extended, such as `_transfer`. This function implements token transfers and is used by `ERC20`, so it can be used to trigger functionality automatically. This is something that can't be done with the `ERC20Mintable` approach.
|
|
|
|
Adding to our previous supply mechanism, we can use this to mint a miner reward for every token transfer that is included in the blockchain.
|
|
|
|
[source,solidity]
|
|
----
|
|
contract ERC20WithAutoMinerReward is ERC20 {
|
|
function _mintMinerReward() internal {
|
|
_mint(block.coinbase, 1000);
|
|
}
|
|
|
|
function _transfer(address from, address to, uint256 value) internal {
|
|
_mintMinerReward();
|
|
super._transfer(from, to, value);
|
|
}
|
|
}
|
|
----
|
|
|
|
Note how we override `_transfer` to first mint the miner reward and then run the original implementation by calling `super._transfer`. This last step is very important to preserve the original semantics of ERC20 transfers.
|
|
|
|
[[wrapping-up]]
|
|
== Wrapping up
|
|
|
|
We've seen two ways to implement ERC20 supply mechanisms: internally through `_mint`, and externally through `ERC20Mintable`. Hopefully this has helped you understand how to use OpenZeppelin and some of the design principles behind it, and you can apply them to your own smart contracts.
|