赞
踩
提示:本文是我在学习智能合约开发过程中的一些思考和总结。在这个复杂且不断发展的领域中,可能存在一些疏漏或不准确之处。我非常欢迎和鼓励大家提出意见和建议,让我们可以共同讨论、纠正错误,并提高我们对区块链技术和智能合约的理解与掌握。希望通过这种开放的交流,我们都能在这一领域得到成长和进步。
ERC20 是一个基于以太坊的智能合约标准库,提供了一种创建新代币的标准方法。ERC20 代币合约可以让任何人在以太坊网络上创建可交易的代币,这些代币可以代表任何东西,如货币、积分等。
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
功能:允许用户销毁(burn)他们的代币,从而减少总供应量。
使用方法:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
contract MyToken is ERC20Burnable {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
_mint(msg.sender, initialSupply);
}
}
主要方法:
burn(uint256 amount)
: 销毁调用者持有的指定数量的代币。burnFrom(address account, uint256 amount)
: 从指定账户销毁指定数量的代币,前提是调用者拥有足够的授权。功能:设定代币的最大供应量上限。
使用方法:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol";
contract MyToken is ERC20Capped {
constructor(uint256 initialSupply, uint256 cap) ERC20("MyToken", "MTK") ERC20Capped(cap) {
_mint(msg.sender, initialSupply);
}
function mint(address to, uint256 amount) public {
_mint(to, amount);
}
}
注意:_mint
方法需要在合约中定义,以便遵循 ERC20Capped
的上限限制。
功能:允许管理员在紧急情况下暂停和恢复代币的所有传输操作。
使用方法:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract MyToken is ERC20Pausable, Ownable { constructor(uint256 initialSupply) ERC20("MyToken", "MTK") { _mint(msg.sender, initialSupply); } function pause() public onlyOwner { _pause(); } function unpause() public onlyOwner { _unpause(); } function _beforeTokenTransfer(address from, address to, uint256 amount) internal override(ERC20, ERC20Pausable) { super._beforeTokenTransfer(from, to, amount); } }
主要方法:
_pause()
: 暂停所有代币转移操作。_unpause()
: 恢复所有代币转移操作。_beforeTokenTransfer
: 在每次代币转移前调用,检查是否已暂停。功能:允许创建代币持有者的快照,并查询过去的余额。
使用方法:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Snapshot.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC20Snapshot, Ownable {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
_mint(msg.sender, initialSupply);
}
function snapshot() public onlyOwner {
_snapshot();
}
}
主要方法:
_snapshot()
: 创建一个新的快照,并返回快照 ID。balanceOfAt(address account, uint256 snapshotId)
: 返回指定账户在指定快照时的余额。totalSupplyAt(uint256 snapshotId)
: 返回在指定快照时的总供应量。功能:允许持有者通过签名离线授权其他账户转移其代币。
使用方法:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
contract MyToken is ERC20Permit {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") ERC20Permit("MyToken") {
_mint(msg.sender, initialSupply);
}
主要方法:
permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
: 根据签名数据批准 spender
转移 owner
的代币。功能:用于治理代币,通过快照记录历史投票权。
使用方法:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; contract MyToken is ERC20Votes { constructor(uint256 initialSupply) ERC20("MyToken", "MTK") ERC20Permit("MyToken") { _mint(msg.sender, initialSupply); } // 需要覆盖 _afterTokenTransfer, _mint, _burn 来处理投票权更新 function _afterTokenTransfer(address from, address to, uint256 amount) internal override(ERC20, ERC20Votes) { super._afterTokenTransfer(from, to, amount); } function _mint(address to, uint256 amount) internal override(ERC20, ERC20Votes) { super._mint(to, amount); } function _burn(address account, uint256 amount) internal override(ERC20, ERC20Votes) { super._burn(account, amount); } }
主要方法:
delegate(address delegatee)
: 委托投票权给 delegatee
。getVotes(address account)
: 获取 account
当前的投票权。getPastVotes(address account, uint256 blockNumber)
: 获取 account
在指定区块号时的投票权。功能:SafeERC20
是一个库,为 ERC20 代币操作提供了安全的包装器。这些包装器可以确保操作不会失败,并且在某些情况下会处理代币合约未按预期返回值的问题。
使用方法:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract MyContract { using SafeERC20 for IERC20; IERC20 private _token; constructor(IERC20 token) { _token = token; } function safeTransfer(address to, uint256 amount) public { _token.safeTransfer(to, amount); } function safeTransferFrom(address from, address to, uint256 amount) public { _token.safeTransferFrom(from, to, amount); } function safeApprove(address spender, uint256 amount) public { _token.safeApprove(spender, amount); } function safeIncreaseAllowance(address spender, uint256 addedValue) public { _token.safeIncreaseAllowance(spender, addedValue); } function safeDecreaseAllowance(address spender, uint256 subtractedValue) public { _token.safeDecreaseAllowance(spender, subtractedValue); }
主要方法:
safeTransfer(IERC20 token, address to, uint256 amount)
: 安全转移代币。safeTransferFrom(IERC20 token, address from, address to, uint256 amount)
: 从一个账户安全转移代币到另一个账户。safeApprove(IERC20 token, address spender, uint256 amount)
: 安全批准代币。safeIncreaseAllowance(IERC20 token, address spender, uint256 addedValue)
: 安全增加允许的代币数量。safeDecreaseAllowance(IERC20 token, address spender, uint256 subtractedValue)
: 安全减少允许的代币数量。功能:TokenTimelock
是一个智能合约,用于锁定 ERC20 代币,直到指定的释放时间。
使用方法:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/TokenTimelock.sol"; contract MyTokenTimelock { IERC20 private _token; TokenTimelock private _timelock; constructor(IERC20 token, address beneficiary, uint256 releaseTime) { _token = token; _timelock = new TokenTimelock(token, beneficiary, releaseTime); } function getTimelockAddress() public view returns (address) { return address(_timelock); } }
主要方法:
TokenTimelock(IERC20 token, address beneficiary, uint256 releaseTime)
: 构造函数,用于初始化代币、受益人和释放时间。release()
: 释放锁定的代币,必须在释放时间之后调用。SafeERC20
来确保代币操作的安全性。Ownable
和 AccessControl
进行权限管理,确保只有授权用户可以执行特定操作。与 USDT 等 ERC20 代币交互时,为什么建议使用 SafeERC20
?
transfer
, transferFrom
, approve
等操作时,不会返回布尔值(true
或 false
),而是直接返回交易结果。这种行为不符合 ERC20 标准,可能会导致在处理这些交易时出现问题。SafeERC20
提供的安全包装函数,可以确保在调用 ERC20 代币函数时,正确处理返回值,并在操作失败时抛出错误。这提高了合约的安全性和可靠性。欢迎访问我的 GitHub 查看更多相关项目,或通过WeChat(ID: lk34041515)与我联系,共同探讨技术问题。
本文由 [Leon-Kay] 学习总结编写,水平有限,内容仅供参考,作为个人记录使用。若有疏漏,请不吝赐教。版权归作者所有,未经授权,禁止转载、摘编或以其他方式使用本文内容。如需合作或转载本文,请联系作者获得授权。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。