ERC20 - OpenZeppelin 文档

本文档介绍了OpenZeppelin Contracts库中与ERC20代币标准相关的接口、合约和实用程序。核心合约实现了EIP中指定的行为,并提供了一系列自定义扩展,例如无gas token批准、销毁token、限制token供应、暂停token转移等。此外,还包括了与ERC20合约交互的多种实用程序。

你没有在阅读当前版本的文档。5.x 是当前版本。

ERC 20

最好在 https://docs.openzeppelin.com/contracts/api/token/erc20 上查看此文档

这组接口、合约和实用程序都与 ERC20 Token Standard 相关。

有关 ERC20 token 的概述以及如何创建 token 合约的演练,请阅读我们的 ERC20 指南

有一些核心合约实现了 EIP 中指定的行为:

此外,还有多个自定义扩展,包括:

  • 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)旨在使用固定的模式,为开发人员提供随时可用、可部署的合约。

Core

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 数量。 默认情况下,此值为零。

当调用 approvetransferFrom 时,此值会更改。

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 设置 spenderowner 的 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 的其他实现可能不会发出这些事件,因为规范中没有要求。

最后,已添加非标准的 decreaseAllowanceincreaseAllowance 函数,以缓解围绕设置 allowance 的众所周知的问题。 请参阅 IERC20.approve

函数

事件

IERC20

constructor(string name_, string symbol_) public

设置 namesymbol 的值。

所有这两个值都是不可变的:它们只能在构造期间设置一次。

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.balanceOfIERC20.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。

要求:

  • fromto 不能为零地址。

  • from 必须至少有 amount 的余额。

  • 调用者必须至少有 amountfrom'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 设置为 spenderowner 的 token 的 allowance。

此内部函数等效于 approve,并且可以用于例如为某些子系统设置自动 allowance 等。

发出一个 Approval 事件。

要求:

  • owner 不能为零地址。

  • spender 不能为零地址。

_spendAllowance(address owner, address spender, uint256 amount) internal

根据花费的 amount 更新 ownerspender allowance。

如果 allowance 无限,则不更新 allowance amount。 如果没有足够的 allowance,则恢复。

可能会发出一个 Approval 事件。

_beforeTokenTransfer(address from, address to, uint256 amount) internal

在任何 token 转移之前调用的 Hook。 这包括 mint 和 burning。

调用条件:

  • fromto 都为非零时,fromamount 个 token 将转移到 to

  • from 为零时,amount 个 token 将被 mint 给 to

  • to 为零时,fromamount 个 token 将被 burned。

  • fromto 永远不会都为零。

要了解有关 Hook 的更多信息,请访问使用 Hook

_afterTokenTransfer(address from, address to, uint256 amount) internal

在任何 token 转移之后调用的 Hook。 这包括 mint 和 burning。

调用条件:

  • fromto 都为非零时,fromamount 个 token 已转移到 to

  • from 为零时,amount 个 token 已被 mint 给 to

  • to 为零时,fromamount 个 token 已被 burned。

  • fromto 永远不会都为零。

要了解有关 Hook 的更多信息,请访问使用 Hook

Extensions

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 设置为 spenderowner 的 token 的 allowance,给定 owner 的签名 approval。

与交易排序相关的 IERC20.approve 具有相同的问题也适用于此处。

发出一个 Approval 事件。

要求:

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 作为 spenderowner 的 token 的授权额度。

IERC20.approve 相关的交易<br>排序问题也适用于此处。

发出一个 Approval 事件。

要求:

  • spender 不能是零地址。

  • deadline 必须是未来的时间戳。

  • vrs 必须是来自 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._burnERC20.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._pausePausable._unpause 内部函数,并具有适当的<br>访问控制,例如使用 AccessControlOwnable。不这样做将<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

Gas 成本

快照是高效的。快照创建是 加粗O(1)加粗。从快照中检索余额或总供应量是 加粗O(log_ _n)加粗,其中 n 是已创建的快照数,尽管特定帐户的 n 通常会小得多, 因为后续快照中的相同余额存储为单个条目。

由于额外的快照簿记,正常的 ERC20 转移存在恒定的开销。此开销 仅对于特定帐户在快照后立即进行的第一次转移才重要。后续 转移将具有正常的成本,直到下一个快照,依此类推。

函数

ERC20

Events

IERC20

_snapshot() → uint256 internal

创建一个新的快照并返回其快照 ID。

发出一个包含相同 ID 的 Snapshot 事件。

_snapshotinternal 的,你必须决定如何以外部方式公开它。它的使用可能仅限于一组 帐户,例如使用 AccessControl,或者可以向公众开放。

虽然某些信任最小化机制(例如分叉)需要一种公开调用 _snapshot 的方式,<br>但你必须考虑到攻击者可能会以两种方式使用它。<br>首先,它可以用于增加从快照中检索值的成本,尽管它的增长速度<br>呈对数级,因此从长远来看,这种攻击无效。其次,它可以用于针对<br>特定帐户并增加其 ERC20 转移的成本,其方式如上面的 Gas 成本<br>部分中所述。<br>我们尚未测量实际数字;如果你对此感兴趣,请与我们联系。
_getCurrentSnapshotId() → uint256 internal

获取当前 snapshotId

balanceOfAt(address account, uint256 snapshotId) → uint256 public

检索创建 snapshotIdaccount 的余额。

totalSupplyAt(uint256 snapshotId) → uint256 public

检索创建 snapshotId 时的总供应量。

_beforeTokenTransfer(address from, address to, uint256 amount) internal

在任何 token 转移之前调用的 Hook。这包括 铸造和燃烧。

调用条件:

  • fromto 都是非零时,fromamount 个 token 将被转移到 to

  • from 为零时,将为 to 铸造 amount 个 token。

  • to 为零时,将烧毁 fromamount 个 token。

  • fromto 永远不会都为零。

要了解有关 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

检索 accounttimepoint 结束时的票数。

要求:

  • 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.DelegateChangedIVotes.DelegateVotesChanged

ERC20VotesComp

import "@openzeppelin/contracts/token/ERC20/extensions/ERC20VotesComp.sol";

ERC20 的扩展,用于支持 Compound 的投票和委托。 此版本与 Compound 的 接口完全匹配,但缺点是仅支持高达 (296 - 1) 的供应量。

如果你需要与 COMP 完全兼容(例如,为了将你的代币与 Governor Alpha 或 Bravo 一起使用),并且你确定 296 的供应上限对你来说足够,你应该使用此合约。<br>否则,请使用此模块的 ERC20Votes 变体。

此扩展保留每个帐户投票权的历史记录(检查点)。可以通过直接调用 delegate 函数,或者通过提供签名以与 delegateBySig 一起使用来委托投票权。投票权可以通过公共访问器 getCurrentVotesgetPriorVotes 进行查询。

默认情况下,代币余额不考虑投票权。这使得转移更便宜。缺点是它 要求用户委托给自己以激活检查点并跟踪他们的投票权。

自从 v4.2 版本可用。

Functions

ERC20Votes

ERC20Permit

EIP712

ERC20

Events

IVotes

IERC5267

IERC20

getCurrentVotes(address account) → uint96 external

getVotes 访问器的 Comp 版本,带有 uint96 返回类型。

getPriorVotes(address account, uint256 blockNumber) → uint96 external

getPastVotes 访问器的 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) internal
decimals() → 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

执行闪电贷。 新代币会被铸造并发送给 receiverreceiver 需要实现 IERC3156FlashBorrower 接口。 在闪电贷结束时,receiver 预计拥有 amount + fee 代币,并将它们批准回代币合约本身,以便 可以将其烧毁。

ERC4626

import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";

ERC4626 "代币化金库标准" 的实现,如 EIP-4626 中定义的那样。

此扩展允许铸造和销毁“份额”(使用 ERC20 继承表示),以换取通过标准化 depositmintredeemburn 工作流程的底层“资产”。 此合约扩展了 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 来表示底层资产的小数位数。

请参阅 IERC20Metadata.decimals

asset() → address public

请参阅 IERC4626.asset

totalAssets() → uint256 public

请参阅 IERC4626.totalAssets

convertToShares(uint256 assets) → uint256 public

请参阅 IERC4626.convertToShares

convertToAssets(uint256 shares) → uint256 public

请参阅 IERC4626.convertToAssets

maxDeposit(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 public

请参阅 IERC4626.previewDeposit

previewMint(uint256 shares) → uint256 public

请参阅 IERC4626.previewMint

previewWithdraw(uint256 assets) → uint256 public

请参阅 IERC4626.previewWithdraw

previewRedeem(uint256 shares) → uint256 public

请参阅 IERC4626.previewRedeem

deposit(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

Presets

这些合约是上述功能的预配置组合。它们可以通过继承使用,也可以作为复制和粘贴其源代码的模型。

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_ROLEMINTER_ROLEPAUSER_ROLE 授予给部署合约的帐户。

请参阅 ERC20.constructor

mint(address to, uint256 amount) public

to 创建 amount 个新 token。

请参阅 ERC20._mint

要求:

  • 调用者必须具有 MINTER_ROLE
pause() public

暂停所有 token 转账。

请参阅 ERC20PausablePausable._pause

要求:

  • 调用者必须具有 PAUSER_ROLE
unpause() public

取消暂停所有 token 转账。

请参阅 ERC20PausablePausable._unpause

要求:

  • 调用者必须具有 PAUSER_ROLE
_beforeTokenTransfer(address from, address to, uint256 amount) internal

ERC20PresetFixedSupply

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

Utilities

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 数量的 tokenfrom 转移到 to,花费 from 给调用合约的授权。 如果 token 不返回值,则假定非恢复调用成功。

safeApprove(contract IERC20 token, address spender, uint256 value) internal

已弃用。此函数存在类似于在 IERC20.approve 中发现的问题,不建议使用。

如果可能,请改用 safeIncreaseAllowancesafeDecreaseAllowance

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 上设置ownerspender 的授权。 在无效签名时恢复。

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转移给受益人。只有在释放时间之后调用才会成功。

← 跨链

ERC 721 →

  • 原文链接: docs.openzeppelin.com/co...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
OpenZeppelin
OpenZeppelin
江湖只有他的大名,没有他的介绍。