Michael.W基于Foundry精读Openzeppelin第40期——ERC20Burnable.sol
- 0. 版本
- 0.1 ERC20Burnable.sol
- 1. 目标合约
- 2. 代码精读
- 2.1 burn(uint256 amount)
- 2.2 burnFrom(address account, uint256 amount)
0. 版本
[openzeppelin]:v4.8.3,[forge-std]:v1.5.6
0.1 ERC20Burnable.sol
Github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/token/ERC20/extensions/ERC20Burnable.sol
ERC20Burnable库是ERC20的拓展。该库允许用户销毁自己和给自己授权的人名下的token。
1. 目标合约
继承ERC20Burnable合约:
Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/src/token/ERC20/extensions/MockERC20Burnable.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;import "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol";contract MockERC20Burnable is ERC20Burnable {constructor(string memory name, string memory symbol)ERC20(name, symbol) {}function mint(address account, uint amount) external {_mint(account, amount);}
}
全部foundry测试合约:
Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/test/token/ERC20/extensions/ERC20Burnable.t.sol
2. 代码精读
2.1 burn(uint256 amount)
调用者销毁自己名下数量为amount的token。
function burn(uint256 amount) public virtual {// 调用ERC20._burn()进行销毁_burn(_msgSender(), amount);}
foundry代码验证:
contract ERC20BurnableTest is Test {MockERC20Burnable private _testing = new MockERC20Burnable("test name", "test symbol");address private user1 = address(1);function setUp() external {_testing.mint(user1, 100);}function test_Burn() external {vm.prank(user1);_testing.burn(1);assertEq(_testing.balanceOf(user1), 100 - 1);// revert if burn more than balancevm.expectRevert("ERC20: burn amount exceeds balance");_testing.burn(100);}
}
2.2 burnFrom(address account, uint256 amount)
调用者销毁account名下数量为amount的token。要求调用者必须拥有account地址足够的授权额度。
注:销毁过程同样会减少account给调用者的授权额度。如果授权额度为type(uint).max
,那么该过程将不做授权额度的检查和更新.
function burnFrom(address account, uint256 amount) public virtual {// 调用ERC20._spendAllowance()进行授权额度的检查和更新_spendAllowance(account, _msgSender(), amount);// 调用ERC20._burn()进行销毁_burn(account, amount);}
foundry代码验证:
contract ERC20BurnableTest is Test {MockERC20Burnable private _testing = new MockERC20Burnable("test name", "test symbol");address private user1 = address(1);address private user2 = address(2);function setUp() external {_testing.mint(user1, 100);}function test_BurnFrom() external {// revert without approvevm.prank(user2);vm.expectRevert("ERC20: insufficient allowance");_testing.burnFrom(user1, 1);// revert if burn more than allowancevm.prank(user1);_testing.approve(user2, 1);vm.prank(user2);vm.expectRevert("ERC20: insufficient allowance");_testing.burnFrom(user1, 2);// revert if burn more than balancevm.prank(user1);_testing.approve(user2, 100 + 1);vm.prank(user2);vm.expectRevert("ERC20: burn amount exceeds balance");_testing.burnFrom(user1, 100 + 1);// passvm.prank(user2);_testing.burnFrom(user1, 10);assertEq(_testing.allowance(user1, user2), 101 - 10);assertEq(_testing.balanceOf(user1), 100 - 10);// allowance not changed if it was set to type(uint).maxvm.prank(user1);_testing.approve(user2, type(uint).max);vm.prank(user2);_testing.burnFrom(user1, 10);assertEq(_testing.allowance(user1, user2), type(uint).max);}
}
ps:
本人热爱图灵,热爱中本聪,热爱V神。
以下是我个人的公众号,如果有技术问题可以关注我的公众号来跟我交流。
同时我也会在这个公众号上每周更新我的原创文章,喜欢的小伙伴或者老伙计可以支持一下!
如果需要转发,麻烦注明作者。十分感谢!
公众号名称:后现代泼痞浪漫主义奠基人