本文档介绍了OpenZeppelin Contracts库中与ERC20代币标准相关的接口、合约和实用程序。核心合约实现了EIP中指定的行为,并提供了一系列自定义扩展,例如无gas token批准、销毁token、限制token供应、暂停token转移等。此外,还包括了与ERC20合约交互的多种实用程序。
你没有在阅读当前版本的文档。5.x 是当前版本。
最好在 https://docs.openzeppelin.com/contracts/api/token/erc20 上查看此文档 |
这组接口、合约和实用程序都与 ERC20 Token Standard 相关。
有关 ERC20 token 的概述以及如何创建 token 合约的演练,请阅读我们的 ERC20 指南。 |
有一些核心合约实现了 EIP 中指定的行为:
IERC20
: 所有 ERC20 实现都应符合的接口。
IERC20Metadata
: 扩展的 ERC20 接口,包括 name
, symbol
和 decimals
函数。
此外,还有多个自定义扩展,包括:
ERC20Permit
: token 的 gasless approval(标准化为 ERC2612)。
ERC20Burnable
: 销毁自己的 token。
ERC20Capped
: 在 mint token 时强制执行 total supply 的上限。
ERC20Pausable
: 暂停 token 转移的能力。
ERC20Snapshot
: 过去 token 余额的有效存储,以便以后在任何时间点查询。
ERC20FlashMint
: 通过 mint 和 burning 临时 token 来实现对闪电贷的 token 级别支持(标准化为 ERC3156)。
ERC20Votes
: 支持投票和投票委托。
ERC20VotesComp
: 支持投票和投票委托(与 Compound 的 token 兼容,具有 uint96 限制)。
ERC20Wrapper
: 用于创建由另一个 ERC20 支持的 ERC20 的包装器,具有 deposit 和 withdraw 方法。与 ERC20Votes
结合使用很有用。
ERC4626
: token 化的 vault,管理由资产(另一个 ERC20)支持的 shares(表示为 ERC20)。
最后,有一些实用程序以各种方式与 ERC20 合约交互。
SafeERC20
: 接口的包装器,无需处理布尔返回值。
TokenTimelock
: 为受益人持有 token,直到指定的时间。
这组核心合约旨在保持不偏不倚,允许开发人员访问 ERC20 中的内部函数(例如 _mint ),并以他们喜欢的方式将其公开为外部函数。另一方面,ERC20 Presets(例如 ERC20PresetMinterPauser )旨在使用固定的模式,为开发人员提供随时可用、可部署的合约。 |
IERC20
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
ERC20 标准的接口,如 EIP 中定义的那样。
函数
事件
totalSupply() → uint256
external返回存在的 token 数量。
balanceOf(address account) → uint256
external返回 account
拥有的 token 数量。
transfer(address to, uint256 amount) → bool
external将 amount
个 token 从调用者的帐户移动到 to
。
返回一个布尔值,指示操作是否成功。
发出一个 transfer
事件。
allowance(address owner, address spender) → uint256
external返回 spender
将被允许代表 owner
通过 transferFrom
支出的剩余 token 数量。 默认情况下,此值为零。
当调用 approve
或 transferFrom
时,此值会更改。
approve(address spender, uint256 amount) → bool
external将 amount
设置为 spender
对调用者的 token 的 allowance。
返回一个布尔值,指示操作是否成功。
请注意,使用此方法更改 allowance 会带来风险,即某人可能会因不幸的交易排序而同时使用旧的和新的 allowance。 缓解此竞争条件的一种可能的解决方案是首先将 spender 的 allowance 减少到 0,然后设置所需的值:https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 |
发出一个 Approval
事件。
transferFrom(address from, address to, uint256 amount) → bool
external使用 allowance 机制将 amount
个 token 从 from
移动到 to
。 然后从调用者的 allowance 中扣除 amount
。
返回一个布尔值,指示操作是否成功。
发出一个 transfer
事件。
Transfer(address indexed from, address indexed to, uint256 value)
event当 value
个 token 从一个帐户 ( from
) 移动到另一个帐户 ( to
) 时发出。
请注意,value
可能为零。
Approval(address indexed owner, address indexed spender, uint256 value)
event当通过调用 approve
设置 spender
对 owner
的 allowance 时发出。 value
是新的 allowance。
IERC20Metadata
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
来自 ERC20 标准的可选元数据函数的接口。
可用版本: v4.1。
函数
IERC20
事件
IERC20
name() → string
external返回 token 的名称。
symbol() → string
external返回 token 的符号。
decimals() → uint8
external返回 token 的小数位数。
ERC20
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
IERC20
接口的实现。
此实现与创建 token 的方式无关。 这意味着必须在使用 _mint
的派生合约中添加供应机制。 有关通用机制,请参阅 ERC20PresetMinterPauser
。
有关详细的撰写,请参阅我们的指南如何实现供应机制](https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226)。 |
decimals
的默认值为 18。 要更改此值,你应该覆盖此函数,使其返回不同的值。
我们遵循了通用的 OpenZeppelin 合约指南:函数在失败时恢复,而不是返回 false
。 尽管如此,此行为是传统的,并且不与 ERC20 应用程序的期望相冲突。
此外,Approval
事件在调用 transferFrom
时发出。 这允许应用程序仅通过侦听上述事件来重建所有帐户的 allowance。 EIP 的其他实现可能不会发出这些事件,因为规范中没有要求。
最后,已添加非标准的 decreaseAllowance
和 increaseAllowance
函数,以缓解围绕设置 allowance 的众所周知的问题。 请参阅 IERC20.approve
。
函数
事件
IERC20
constructor(string name_, string symbol_)
public所有这两个值都是不可变的:它们只能在构造期间设置一次。
name() → string
public返回 token 的名称。
symbol() → string
public返回 token 的符号,通常是名称的较短版本。
decimals() → uint8
public返回用于获取其用户表示形式的小数位数。 例如,如果 decimals
等于 2
,则应向用户显示 505
个 token 的余额为 5.05
( 505 / 10 ** 2
)。
Token 通常选择 18 的值,模仿 Ether 和 Wei 之间的关系。 这是此函数返回的默认值,除非它被覆盖。
此信息仅用于显示目的:它绝不会影响合约的任何算术运算,包括 IERC20.balanceOf 和 IERC20.transfer 。 |
totalSupply() → uint256
public请参阅 IERC20.totalSupply
。
balanceOf(address account) → uint256
public请参阅 IERC20.balanceOf
。
transfer(address to, uint256 amount) → bool
public请参阅 IERC20.transfer
。
要求:
to
不能为零地址。
调用者必须至少有 amount
的余额。
allowance(address owner, address spender) → uint256
public请参阅 IERC20.allowance
。
approve(address spender, uint256 amount) → bool
public请参阅 IERC20.approve
。
如果 amount 是最大 uint256 ,则不会在 transferFrom 上更新 allowance。 这在语义上等同于无限 approval。 |
要求:
spender
不能为零地址。transferFrom(address from, address to, uint256 amount) → bool
public请参阅 IERC20.transferFrom
。
发出一个 Approval
事件,指示已更新的 allowance。 EIP 不需要这样做。 请参阅 ERC20
开头的注释。
如果当前 allowance 是最大 uint256 ,则不会更新 allowance。 |
要求:
from
和 to
不能为零地址。
from
必须至少有 amount
的余额。
调用者必须至少有 amount
的 from
's token 的 allowance。
increaseAllowance(address spender, uint256 addedValue) → bool
public以原子方式将授予 spender
的 allowance 增加调用者。
这是一种替代 approve
的方法,可以用作缓解 IERC20.approve
中描述的问题的方法。
发出一个 Approval
事件,指示已更新的 allowance。
要求:
spender
不能为零地址。decreaseAllowance(address spender, uint256 subtractedValue) → bool
public以原子方式将授予 spender
的 allowance 减少调用者。
这是一种替代 approve
的方法,可以用作缓解 IERC20.approve
中描述的问题的方法。
发出一个 Approval
事件,指示已更新的 allowance。
要求:
spender
不能为零地址。
spender
必须至少具有 subtractedValue
的调用者 allowance。
_transfer(address from, address to, uint256 amount)
internal将 amount
个 token 从 from
移动到 to
。
此内部函数等效于 transfer
,并且可以用于例如实现自动 token 费用、削减机制等。
发出一个 transfer
事件。
要求:
from
不能为零地址。
to
不能为零地址。
from
必须至少有 amount
的余额。
_mint(address account, uint256 amount)
internal创建 amount
个 token 并将其分配给 account
,从而增加 total supply。
发出一个 transfer
事件,其中 from
设置为零地址。
要求:
account
不能为零地址。_burn(address account, uint256 amount)
internal销毁 account
中的 amount
个 token,从而减少 total supply。
发出一个 transfer
事件,其中 to
设置为零地址。
要求:
account
不能为零地址。
account
必须至少有 amount
个 token。
_approve(address owner, address spender, uint256 amount)
internal将 amount
设置为 spender
对 owner
的 token 的 allowance。
此内部函数等效于 approve
,并且可以用于例如为某些子系统设置自动 allowance 等。
发出一个 Approval
事件。
要求:
owner
不能为零地址。
spender
不能为零地址。
_spendAllowance(address owner, address spender, uint256 amount)
internal根据花费的 amount
更新 owner
的 spender
allowance。
如果 allowance 无限,则不更新 allowance amount。 如果没有足够的 allowance,则恢复。
可能会发出一个 Approval
事件。
_beforeTokenTransfer(address from, address to, uint256 amount)
internal在任何 token 转移之前调用的 Hook。 这包括 mint 和 burning。
调用条件:
当 from
和 to
都为非零时,from
的 amount
个 token 将转移到 to
。
当 from
为零时,amount
个 token 将被 mint 给 to
。
当 to
为零时,from
的 amount
个 token 将被 burned。
from
和 to
永远不会都为零。
要了解有关 Hook 的更多信息,请访问使用 Hook。
_afterTokenTransfer(address from, address to, uint256 amount)
internal在任何 token 转移之后调用的 Hook。 这包括 mint 和 burning。
调用条件:
当 from
和 to
都为非零时,from
的 amount
个 token 已转移到 to
。
当 from
为零时,amount
个 token 已被 mint 给 to
。
当 to
为零时,from
的 amount
个 token 已被 burned。
from
和 to
永远不会都为零。
要了解有关 Hook 的更多信息,请访问使用 Hook。
IERC20Permit
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
ERC20 Permit 扩展的接口,允许通过签名进行 approval,如 EIP-2612 中定义的那样。
添加了 permit
方法,该方法可用于通过呈现由帐户签名的消息来更改帐户的 ERC20 allowance(请参阅 IERC20.allowance
)。 通过不依赖于 IERC20.approve
,token 持有者帐户不需要发送交易,因此根本不需要持有 Ether。
关于 permit
的使用,有两个重要的注意事项。 第一个注意事项是,有效的 permit 签名表示 allowance,不应假定其传达其他含义。 特别是,不应将其视为以任何特定方式花费 allowance 的意图。 第二个注意事项是,由于 permit 具有内置的重放保护并且可以由任何人提交,因此它们可以被抢跑。 使用 permit 的协议应考虑到这一点,并允许 permit
调用失败。 结合这两个方面,通常可以推荐的模式是:
function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
doThing(..., value);
}
function doThing(..., uint256 value) public {
token.safeTransferFrom(msg.sender, address(this), value);
...
}
请注意:1) msg.sender
用作所有者,对签名者的意图没有歧义,以及 2) 使用 try/catch
允许 permit 失败,并使代码能够容忍抢跑。 (另请参阅 SafeERC20.safeTransferFrom
)。
此外,请注意,智能合约钱包(如 Argent 或 Safe)无法生成 permit 签名,因此合约应具有不依赖于 permit 的入口点。
函数
permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external将 value
设置为 spender
对 owner
的 token 的 allowance,给定 owner
的签名 approval。
与交易排序相关的 IERC20.approve 具有相同的问题也适用于此处。 |
发出一个 Approval
事件。
要求:
spender
不能为零地址。
deadline
必须是未来的时间戳。
v
、r
和 s
- allowance(owner, spender)
Events
IERC5267
IERC20
constructor(string name)
internal使用 name
参数初始化 EIP712
域名分隔符,并将 version
设置为 "1"
。
最好使用与定义为 ERC20 token 名称相同的 name
。
permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
public给定 owner
的签名批准,设置 value
作为 spender
对 owner
的 token 的授权额度。
与 IERC20.approve 相关的交易<br>排序问题也适用于此处。 |
发出一个 Approval
事件。
要求:
spender
不能是零地址。
deadline
必须是未来的时间戳。
v
、r
和 s
必须是来自 owner
的有效的 secp256k1
签名
覆盖 EIP712 格式的函数参数。
签名必须使用 owner
的当前 nonce(参见 nonces
)。
有关签名格式的更多信息,请参见 相关EIP部分。
请参见上面的安全注意事项。 |
nonces(address owner) → uint256
public返回 owner
的当前 nonce。每当为 permit
生成签名时,必须包含此值。
每次成功调用 permit
都会将 owner
的 nonce 增加 1。这
可以防止签名被多次使用。
DOMAIN_SEPARATOR() → bytes32
external返回用于 permit
签名的编码中的域名分隔符,如 EIP712
所定义。
_useNonce(address owner) → uint256 current
internal“使用一个 nonce”:返回当前值并递增。
自 v4.1 起可用。
ERC20Burnable
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
ERC20
的扩展,允许 token 持有者销毁他们自己的 token 和他们拥有授权的 token,这可以通过链下方式识别(通过事件分析)。
函数
ERC20
Events
IERC20
burn(uint256 amount)
public从调用者销毁 amount
个 token。
请参见 ERC20._burn
。
burnFrom(address account, uint256 amount)
public从 account
销毁 amount
个 token,从调用者的
授权额度中扣除。
请参见 ERC20._burn
和 ERC20.allowance
。
要求:
accounts
的 token 的 amount
授权额度。ERC20Capped
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol";
ERC20
的扩展,它为 token 的供应量添加了一个上限。
函数
ERC20
Events
IERC20
constructor(uint256 cap_)
internal设置 cap
的值。此值是不可变的,只能
在构造期间设置一次。
cap() → uint256
public返回 token 总供应量的上限。
_mint(address account, uint256 amount)
internal请参见 ERC20._mint
。
ERC20Pausable
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol";
具有可暂停的 token 转移、铸造和燃烧功能的 ERC20 token。
适用于诸如防止在评估期结束前进行交易的场景,或者在出现巨大 bug 时使用紧急开关来冻结所有 token 转移。
此合约不包含公共的暂停和取消暂停功能。除了继承此合约之外,你还必须定义这两个函数,调用<br>Pausable._pause 和 Pausable._unpause 内部函数,并具有适当的<br>访问控制,例如使用 AccessControl 或 Ownable 。不这样做将<br>使合约无法暂停。 |
函数
Pausable
ERC20
Events
Pausable
IERC20
_beforeTokenTransfer(address from, address to, uint256 amount)
internal请参见 ERC20._beforeTokenTransfer
。
要求:
ERC20Snapshot
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Snapshot.sol";
此合约使用快照机制扩展了 ERC20 token。创建快照时,将记录当时的余额和 总供应量,以供以后访问。
这可以用于安全地创建基于 token 余额的机制,例如无需信任的分红或加权投票。 在简单的实现中,可以通过重用来自不同 帐户的相同余额来执行“双重支出”攻击。通过使用快照来计算分红或投票权,这些攻击不再适用。它也可以 用于创建高效的 ERC20 分叉机制。
快照由内部 _snapshot
函数创建,该函数将发出 Snapshot
事件并返回一个
快照 ID。要获取快照时的总供应量,请使用快照
ID 调用函数 totalSupplyAt
。要获取快照时帐户的余额,请使用快照 ID
和帐户地址调用 balanceOfAt
函数。
可以通过覆盖 _getCurrentSnapshotId 方法来自定义快照策略。例如,让它<br>返回 block.number 将触发在每个新区块开始时创建快照。覆盖此<br>函数时,请注意其结果的单调性。非单调快照 ID 将破坏合约。 |
使用此方法为每个区块实现快照会产生大量的 gas 成本。对于 gas 效率高的
替代方案,请考虑 ERC20Votes
。
快照是高效的。快照创建是 加粗O(1)加粗。从快照中检索余额或总供应量是 加粗O(log_ _n)加粗,其中 n 是已创建的快照数,尽管特定帐户的 n 通常会小得多, 因为后续快照中的相同余额存储为单个条目。
由于额外的快照簿记,正常的 ERC20 转移存在恒定的开销。此开销 仅对于特定帐户在快照后立即进行的第一次转移才重要。后续 转移将具有正常的成本,直到下一个快照,依此类推。
函数
ERC20
Events
IERC20
_snapshot() → uint256
internal创建一个新的快照并返回其快照 ID。
发出一个包含相同 ID 的 Snapshot
事件。
_snapshot
是 internal
的,你必须决定如何以外部方式公开它。它的使用可能仅限于一组
帐户,例如使用 AccessControl
,或者可以向公众开放。
虽然某些信任最小化机制(例如分叉)需要一种公开调用 _snapshot 的方式,<br>但你必须考虑到攻击者可能会以两种方式使用它。<br>首先,它可以用于增加从快照中检索值的成本,尽管它的增长速度<br>呈对数级,因此从长远来看,这种攻击无效。其次,它可以用于针对<br>特定帐户并增加其 ERC20 转移的成本,其方式如上面的 Gas 成本<br>部分中所述。<br>我们尚未测量实际数字;如果你对此感兴趣,请与我们联系。 |
_getCurrentSnapshotId() → uint256
internal获取当前 snapshotId
balanceOfAt(address account, uint256 snapshotId) → uint256
public检索创建 snapshotId
时 account
的余额。
totalSupplyAt(uint256 snapshotId) → uint256
public检索创建 snapshotId
时的总供应量。
_beforeTokenTransfer(address from, address to, uint256 amount)
internal在任何 token 转移之前调用的 Hook。这包括 铸造和燃烧。
调用条件:
当 from
和 to
都是非零时,from
的 amount
个 token
将被转移到 to
。
当 from
为零时,将为 to
铸造 amount
个 token。
当 to
为零时,将烧毁 from
的 amount
个 token。
from
和 to
永远不会都为零。
要了解有关 hook 的更多信息,请访问使用 Hook。
Snapshot(uint256 id)
event由 _snapshot
发出,当创建一个由 id
标识的快照时。
ERC20Votes
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
ERC20 的扩展,支持类似 Compound 的投票和委托。此版本比 Compound 的版本更通用, 并且支持高达 2224 - 1 的 token 供应,而 COMP 仅限于 296 - 1。
- approve(spender, amount) |
Events
IVotes
IERC5267
IERC20
clock() → uint48
public用于标记检查点的时钟。可以被覆盖以实现基于时间戳的检查点(和投票)。
CLOCK_MODE() → string
public时钟的描述
checkpoints(address account, uint32 pos) → struct ERC20Votes.Checkpoint
public获取 account
的第 pos
个检查点。
numCheckpoints(address account) → uint32
public获取 account
的检查点数量。
delegates(address account) → address
public获取 account
当前委托到的地址。
getVotes(address account) → uint256
public获取 account
当前的投票余额
getPastVotes(address account, uint256 timepoint) → uint256
public检索 account
在 timepoint
结束时的票数。
要求:
timepoint
必须是过去的时间getPastTotalSupply(uint256 timepoint) → uint256
public检索 timepoint
结束时的 totalSupply
。请注意,该值是所有余额的总和。
它不是所有委托投票的总和!
要求:
timepoint
必须是过去的时间delegate(address delegatee)
public将投票权从发送者委托给 delegatee
。
delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)
public将投票权从签名者委托给 delegatee
_maxSupply() → uint224
internal最大代币供应量。 默认为 type(uint224).max
(2224 - 1)。
_mint(address account, uint256 amount)
internal在增加 totalSupply 后对其进行快照。
_burn(address account, uint256 amount)
internal在减少 totalSupply 后对其进行快照。
_afterTokenTransfer(address from, address to, uint256 amount)
internal在代币转账时移动投票权。
发出 IVotes.DelegateVotesChanged
事件。
_delegate(address delegator, address delegatee)
internal将 delegator
的委托更改为 delegatee
。
发出事件 IVotes.DelegateChanged
和 IVotes.DelegateVotesChanged
。
ERC20VotesComp
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20VotesComp.sol";
ERC20 的扩展,用于支持 Compound 的投票和委托。 此版本与 Compound 的 接口完全匹配,但缺点是仅支持高达 (296 - 1) 的供应量。
如果你需要与 COMP 完全兼容(例如,为了将你的代币与 Governor Alpha 或 Bravo 一起使用),并且你确定 296 的供应上限对你来说足够,你应该使用此合约。<br>否则,请使用此模块的 ERC20Votes 变体。 |
此扩展保留每个帐户投票权的历史记录(检查点)。可以通过直接调用 delegate
函数,或者通过提供签名以与 delegateBySig
一起使用来委托投票权。投票权可以通过公共访问器 getCurrentVotes
和 getPriorVotes
进行查询。
默认情况下,代币余额不考虑投票权。这使得转移更便宜。缺点是它 要求用户委托给自己以激活检查点并跟踪他们的投票权。
自从 v4.2 版本可用。
Functions
ERC20Votes
ERC20Permit
EIP712
ERC20
Events
IVotes
IERC5267
IERC20
getCurrentVotes(address account) → uint96
externalgetVotes
访问器的 Comp 版本,带有 uint96
返回类型。
getPriorVotes(address account, uint256 blockNumber) → uint96
externalgetPastVotes
访问器的 Comp 版本,带有 uint96
返回类型。
_maxSupply() → uint224
internal最大代币供应量。 减少到 type(uint96).max
(296 - 1) 以适应 COMP 接口。
ERC20Wrapper
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Wrapper.sol";
ERC20 代币合约的扩展,用于支持代币包装。
用户可以存入和提取“底层代币”,并收到匹配数量的“包装代币”。这与其他模块结合使用时很有用。例如,将此包装机制与 ERC20Votes
结合使用将允许将现有的“基本”ERC20 包装成治理代币。
自从 v4.2 版本可用。
Functions
ERC20
Events
IERC20
constructor(contract IERC20 underlyingToken)
internaldecimals() → uint8
public参见 ERC20.decimals
。
underlying() → contract IERC20
public返回正在包装的底层 ERC-20 代币的地址。
depositFor(address account, uint256 amount) → bool
public允许用户存入底层代币并铸造相应数量的包装代币。
withdrawTo(address account, uint256 amount) → bool
public允许用户销毁一定数量的包装代币并提取相应数量的底层代币。
_recover(address account) → uint256
internal铸造包装代币以覆盖可能因错误转移的任何 underlyingTokens。 可以在需要时通过访问控制公开的内部 函数。
ERC20FlashMint
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol";
ERC3156 闪电贷扩展的实现,如 ERC-3156 中定义的那样。
添加了 flashLoan
方法,该方法在代币级别提供闪电贷支持。 默认情况下没有费用,但是可以通过覆盖 flashFee
来更改此费用。
自从 v4.1 版本可用。
Functions
ERC20
Events
IERC20
maxFlashLoan(address token) → uint256
public返回可用于贷款的最大代币数量。
flashFee(address token, uint256 amount) → uint256
public返回执行闪电贷时应用的费用。 此函数调用
_flashFee
函数,该函数返回执行闪电贷时应用的费用。
_flashFee(address token, uint256 amount) → uint256
internal返回执行闪电贷时应用的费用。 默认情况下,此 实现具有 0 费用。 可以重载此函数以使 闪电贷的机制具有通货紧缩性。
_flashFeeReceiver() → address
internal返回闪电费用的接收者地址。 默认情况下,此 实现返回地址(0),这意味着费用金额将被烧毁。 可以重载此函数以更改费用接收者。
flashLoan(contract IERC3156FlashBorrower receiver, address token, uint256 amount, bytes data) → bool
public执行闪电贷。 新代币会被铸造并发送给
receiver
,receiver
需要实现 IERC3156FlashBorrower
接口。 在闪电贷结束时,receiver
预计拥有
amount + fee 代币,并将它们批准回代币合约本身,以便
可以将其烧毁。
ERC4626
import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
ERC4626 "代币化金库标准" 的实现,如 EIP-4626 中定义的那样。
此扩展允许铸造和销毁“份额”(使用 ERC20 继承表示),以换取通过标准化 deposit
、mint
、redeem
和 burn
工作流程的底层“资产”。 此合约扩展了
ERC20 标准。 与其一起包含的任何其他扩展都会影响此合约表示的“份额”代币,而不是作为独立合约的“资产”代币。
在空的(或几乎空的)ERC-4626 金库中,存款面临很高的风险,可能会通过抢先交易被盗,通过对金库进行“捐赠”来膨胀份额的价格。<br>这通常被称为捐赠或通货膨胀攻击,本质上是滑点问题。 金库部署者可以通过进行非同小可的资产初始存款来防止这种攻击,从而使价格操纵变得不可行。 提款也可能受到滑点的影响。 用户可以通过验证收到的金额是否符合预期来防止这种攻击以及一般的意外滑点,使用执行这些检查的包装器,例如 ERC4626Router。<br>自从 v4.9 以来,此实现使用虚拟资产和份额来降低该风险。 _decimalsOffset() <br>对应于底层资产的小数位数与金库小数位数之间的十进制表示中的偏移量。 此偏移量还决定了金库中虚拟份额与虚拟资产的比率,而金库本身决定了初始汇率。 虽然不能完全阻止攻击,但分析表明,由于被虚拟股份捕获的价值(来自攻击者的捐赠)与攻击者的预期收益相匹配,因此默认偏移量 (0) 使其无利可图。 偏移量越大,攻击的成本就比盈利高出几个数量级。 有关底层数学的更多详细信息,请参见此处。<br>这种方法的缺点是虚拟份额确实捕获了(非常小的)价值的一部分,这些价值正在累积到金库中。 此外,如果金库遭受损失,用户试图退出金库,虚拟份额和资产将导致第一个退出金库的用户遭受的损失减少,这损害了遭受更大损失的最后一个用户。 愿意恢复到 v4.9 之前的行为的开发人员只需要覆盖 _convertToShares 和 _convertToAssets 函数即可。<br>要了解更多信息,请查看我们的 ERC-4626 指南。 |
自从 v4.7 版本可用。
Functions
事件
IERC4626
IERC20
constructor(contract IERC20 asset_)
internal设置底层资产合约。这必须是一个兼容 ERC20 的合约(ERC20 或 ERC777)。
decimals() → uint8
public小数位数是通过在底层资产的小数位数之上添加小数偏移量来计算的。这个“原始”值在 vault 合约的构造过程中被缓存。如果此读取操作失败(例如,资产尚未创建),则默认使用 18 来表示底层资产的小数位数。
asset() → address
public请参阅 IERC4626.asset
。
totalAssets() → uint256
public请参阅 IERC4626.totalAssets
。
convertToShares(uint256 assets) → uint256
publicconvertToAssets(uint256 shares) → uint256
publicmaxDeposit(address) → uint256
public请参阅 IERC4626.maxDeposit
。
maxMint(address) → uint256
public请参阅 IERC4626.maxMint
。
maxWithdraw(address owner) → uint256
public请参阅 IERC4626.maxWithdraw
。
maxRedeem(address owner) → uint256
public请参阅 IERC4626.maxRedeem
。
previewDeposit(uint256 assets) → uint256
publicpreviewMint(uint256 shares) → uint256
public请参阅 IERC4626.previewMint
。
previewWithdraw(uint256 assets) → uint256
publicpreviewRedeem(uint256 shares) → uint256
publicdeposit(uint256 assets, address receiver) → uint256
public请参阅 IERC4626.deposit
。
mint(uint256 shares, address receiver) → uint256
public请参阅 IERC4626.mint
。
与deposit
相反,即使 vault 处于 share 的价格为零的状态,也允许增发。
在这种情况下,share 将被增发,而无需存入任何资产。
withdraw(uint256 assets, address receiver, address owner) → uint256
public请参阅 IERC4626.withdraw
。
redeem(uint256 shares, address receiver, address owner) → uint256
public请参阅 IERC4626.redeem
。
_convertToShares(uint256 assets, enum Math.Rounding rounding) → uint256
internal支持舍入方向的内部转换函数(从资产到 share)。
_convertToAssets(uint256 shares, enum Math.Rounding rounding) → uint256
internal支持舍入方向的内部转换函数(从 share 到资产)。
_deposit(address caller, address receiver, uint256 assets, uint256 shares)
internal存款/增发的常用工作流程。
_withdraw(address caller, address receiver, address owner, uint256 assets, uint256 shares)
internal提取/赎回的常用工作流程。
_decimalsOffset() → uint8
internal这些合约是上述功能的预配置组合。它们可以通过继承使用,也可以作为复制和粘贴其源代码的模型。
ERC20PresetMinterPauser
import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol";
ERC20
token,包括:
持有者可以燃烧(销毁)他们的 token
一个允许增发 token(创建)的增发者角色
一个允许停止所有 token 转账的暂停者角色
此合约使用 AccessControl
来使用不同的角色锁定许可函数 - 前往其文档了解详细信息。
部署合约的帐户将被授予增发者和暂停者角色,以及默认的管理角色,这将使其能够将增发者和暂停者角色授予其他帐户。
不推荐使用,推荐使用 Contracts Wizard。
函数
可暂停的
ERC20Burnable
ERC20
AccessControlEnumerable
AccessControl
事件
可暂停的
IERC20
IAccessControl
constructor(string name, string symbol)
public将 DEFAULT_ADMIN_ROLE
、MINTER_ROLE
和 PAUSER_ROLE
授予给部署合约的帐户。
请参阅 ERC20.constructor
。
mint(address to, uint256 amount)
public为 to
创建 amount
个新 token。
请参阅 ERC20._mint
。
要求:
MINTER_ROLE
。pause()
public暂停所有 token 转账。
请参阅 ERC20Pausable
和 Pausable._pause
。
要求:
PAUSER_ROLE
。unpause()
public取消暂停所有 token 转账。
请参阅 ERC20Pausable
和 Pausable._unpause
。
要求:
PAUSER_ROLE
。_beforeTokenTransfer(address from, address to, uint256 amount)
internalERC20PresetFixedSupply
import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol";
ERC20
token,包括:
预先铸造的初始供应量
持有者可以燃烧(销毁)他们的 token
没有访问控制机制(用于增发/暂停),因此没有治理
此合约使用 ERC20Burnable
来包含燃烧功能 - 前往其文档了解详细信息。
自 v3.4 起可用。
不推荐使用,推荐使用 Contracts Wizard。
函数
ERC20Burnable
ERC20
事件
IERC20
constructor(string name, string symbol, uint256 initialSupply, address owner)
public增发 initialSupply
数量的 token 并将其转移给 owner
。
请参阅 ERC20.constructor
。
SafeERC20
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
ERC20 操作的包装器,在失败时抛出异常(当 token
合约返回 false 时)。还支持不返回值(而是在失败时恢复或
抛出异常)的 Token,假定非恢复调用成功。
要使用此库,你可以向你的合约添加一个 using SafeERC20 for IERC20;
语句,
它允许你将安全操作称为 token.safeTransfer(…)
等。
函数
safeTransfer(contract IERC20 token, address to, uint256 value)
internal将 value
数量的 token
从调用合约转移到 to
。如果 token
不返回值,
则假定非恢复调用成功。
safeTransferFrom(contract IERC20 token, address from, address to, uint256 value)
internal将 value
数量的 token
从 from
转移到 to
,花费 from
给调用合约的授权。
如果 token
不返回值,则假定非恢复调用成功。
safeApprove(contract IERC20 token, address spender, uint256 value)
internal已弃用。此函数存在类似于在
IERC20.approve
中发现的问题,不建议使用。
如果可能,请改用 safeIncreaseAllowance
和
safeDecreaseAllowance
。
safeIncreaseAllowance(contract IERC20 token, address spender, uint256 value)
internal将调用合约对 spender
的授权增加 value
。如果 token
不返回值,
则假定非恢复调用成功。
safeDecreaseAllowance(contract IERC20 token, address spender, uint256 value)
internal将调用合约对 spender
的授权减少 value
。如果 token
不返回值,
则假定非恢复调用成功。
forceApprove(contract IERC20 token, address spender, uint256 value)
internal将调用合约对 spender
的授权设置为 value
。如果 token
不返回值,
则假定非恢复调用成功。旨在与需要在将其设置为非零值之前将授权
设置为零的 token 一起使用,例如 USDT。
safePermit(contract IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
internal使用 ERC-2612 签名在 token
上设置owner
对 spender
的授权。
在无效签名时恢复。
TokenTimelock
import "@openzeppelin/contracts/token/ERC20/utils/TokenTimelock.sol";
一个 token 持有者合约,它将允许受益人在给定的释放时间后提取 token。
适用于简单的 vesting 计划,例如“顾问在 1 年后获得他们的所有 token”。
函数
constructor(contract IERC20 token_, address beneficiary_, uint256 releaseTime_)
public部署一个 timelock 实例,该实例能够持有指定的 token,并且只有在
releaseTime_
之后调用 release
时,才会将其释放给 beneficiary_
。释放时间指定为 Unix 时间戳
(以秒为单位)。
token() → contract IERC20
public返回持有的 token。
beneficiary() → address
public返回将收到 token 的受益人。
releaseTime() → uint256
public返回自 Unix 纪元(即 Unix 时间戳)以来以秒为单位的 token 释放时间。
release()
public将 timelock 持有的 token转移给受益人。只有在释放时间之后调用才会成功。
- 原文链接: docs.openzeppelin.com/co...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!