参考
参考资料
可销毁代币
首先,这里认为已经创建好了 truffle
solidity
项目。
npm install @openzeppelin/contracts@3.4.0
npm install @truffle/hdwallet-provider // 部署脚本
整个项目如下
--contracts
----ERC20WithBurnable.sol
--migrations
----2_deploy_ERC20WithBurnable.js
--.secret
--truffle-config.js
ERC20WithBurnable.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| pragma solidity >=0.4.21 <0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";
contract ERC20WithBurnable is ERC20, ERC20Burnable { constructor( string memory name, string memory symbol, uint256 totalSupply ) public ERC20(name, symbol) { _mint(msg.sender, totalSupply * (10 ** decimals())); } }
|
细节
我们先看 ERC20
的内容
1 2 3 4 5 6 7 8 9
| function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); }
|
我们可以看到里面已经有一个 burn
燃烧方法,那为什么还需要继承 ERC20Burnable
?
这是因为,ERC20
的 _burn
的修饰是 internal
,为内部调用,外部调用不了,所以,需要继承 ERC20Burnable
,因为,该合约进行了调用该方法,内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| pragma solidity >=0.6.0 <0.8.0;
import "../../utils/Context.sol"; import "./ERC20.sol";
abstract contract ERC20Burnable is Context, ERC20 { using SafeMath for uint256;
function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); }
function burnFrom(address account, uint256 amount) public virtual { uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
_approve(account, _msgSender(), decreasedAllowance); _burn(account, amount); } }
|
可以发现,该 ERC20Burnable
调用了 ERC20
的 _burn
方法,并进行了 public
修饰。
让我们再来关注一下, _burn
的实现。
1 2 3 4 5 6 7 8 9
| function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); }
|
- 首先判断账户不是
0x0000000
账户
_beforeTokenTransfer
是一个未实现方法,后面可以继承合约,实现这个方法,然后,在销毁前做一些操作
- 接着从自身账户减去相应数量的代币
- 总量中也减去该数量的代币
- 发出转移给
0x00000
的事件
事实上,这些币是真的销毁了,而没有转给 0x00000
账户。
我们接着看另一个销毁方法 burnFrom
1 2 3 4 5 6
| function burnFrom(address account, uint256 amount) public virtual { uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
_approve(account, _msgSender(), decreasedAllowance); _burn(account, amount); }
|
这个可以参考一下
的 transferForm
。
互动
我们把合约的内容改为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| pragma solidity >=0.4.21 <0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";
contract ERC20WithBurnable is ERC20, ERC20Burnable {
string public burnMsg;
constructor( string memory name, string memory symbol, uint256 totalSupply ) public ERC20(name, symbol) { _mint(msg.sender, totalSupply * (10 ** decimals())); }
function _beforeTokenTransfer(address from, address to, uint256 amount) internal override { burnMsg = "second"; } }
|
然后燃烧的时候,就能够调用 _beforeTokenTransfer
方法了。