本文档介绍了OpenZeppelin Contracts库中的实用工具合约和库,用于提高智能合约的安全性、处理新型数据类型以及安全地使用底层原语。包括安全工具(如Pausable和ReentrancyGuard),以及用于处理地址、数组和字符串的库。此外,还介绍了用于处理计数器、可枚举映射和集合的实用工具,以及安全使用CREATE2操作码的工具。
你当前阅读的不是此文档的最新版本。5.x 是当前版本。
在 https://docs.openzeppelin.com/contracts/api/utils 查看此文档效果更佳 |
包含实用函数的各种合约和库,你可以使用它们来提高安全性、处理新的数据类型或安全地使用底层原语。
安全工具包括:
Pausable
: 提供了一种简单的方法来暂停合约中的活动(通常是为了应对外部威胁)。
ReentrancyGuard
: 保护你免受重入调用。
Address
、Arrays
和 Strings
库提供了更多与这些原生数据类型相关的操作,而 SafeCast
增加了在不同的有符号和无符号数字类型之间安全转换的方法。
对于新的数据类型:
Counters
: 一种获取只能递增或递减的计数器的简单方法。对于 ID 生成、计数合约活动等非常有用。
EnumerableMap
: 类似于 Solidity 的 mapping
类型,但具有键值枚举:这将让你知道映射有多少条目,并遍历它们(mapping
无法做到)。
EnumerableSet
: 类似于 EnumerableMap
,但用于集合。可用于存储特权帐户、已颁发的 ID 等。
因为 Solidity 不支持泛型类型,EnumerableMap 与 EnumerableSet 被专门用于有限数量的键值类型。<br>从 v3.0 开始,EnumerableMap 支持 uint256 → address ( UintToAddressMap ),EnumerableSet 支持 address 和 uint256 ( AddressSet 和 UintSet )。 |
最后,Create2
包含安全使用 CREATE2
EVM 操作码的所有必要实用工具,而无需处理底层汇编。
Pausable
合约模块,允许子项实现紧急停止机制,该机制可以由授权帐户触发。
此模块通过继承使用。它将提供修饰符 whenNotPaused
和 whenPaused
,这些修饰符可以应用于合约的函数。请注意,仅仅包含此模块不会使它们可暂停,只有在修饰符就位后才会可暂停。
修饰符
函数
事件
whenNotPaused()
修饰符修饰符,使函数仅在合约未暂停时可调用。
要求:
whenPaused()
修饰符修饰符,使函数仅在合约暂停时可调用。
要求:
constructor()
内部函数以未暂停状态初始化合约。
paused() → bool
公共函数如果合约已暂停,则返回 true,否则返回 false。
_pause()
内部函数触发停止状态。
要求:
_unpause()
内部函数返回正常状态。
要求:
Paused(address account)
事件当暂停由 account
触发时发出。
Unpaused(address account)
事件当暂停由 account
解除时发出。
ReentrancyGuard
合约模块,有助于防止对函数的重入调用。
继承自 ReentrancyGuard
将使 nonReentrant
修饰符可用,该修饰符可应用于函数以确保没有对它们的嵌套(重入)调用。
请注意,由于存在单个 nonReentrant
保护,因此标记为 nonReentrant
的函数可能不会相互调用。可以通过使这些函数成为 private
,然后向它们添加 external
nonReentrant
入口点来解决此问题。
如果你想了解更多关于重入以及防止重入的替代方法,请查看我们的博文 伊斯坦布尔之后的重入。 |
修饰符
函数
nonReentrant()
修饰符防止合约直接或间接地调用自身。
不支持从另一个 nonReentrant
函数调用 nonReentrant
函数。可以通过使 nonReentrant
函数为 external,并使其调用执行实际工作的 private
函数来防止这种情况发生。
constructor()
内部函数Address
与地址类型相关的函数的集合
函数
isContract(address account) → bool
内部函数如果 account
是合约,则返回 true。
假设此函数返回 false 的地址是外部拥有的帐户 (EOA) 而不是合约是不安全的。<br>其中,isContract 将为以下类型的地址返回 false:<br>- 外部拥有的帐户<br> <br>- 正在构造的合约<br> <br>- 将创建合约的地址<br> <br>- 曾经存在合约但已被销毁的地址 |
sendValue(address payable recipient, uint256 amount)
内部函数Solidity 的 transfer
的替代方案:将 amount
wei 发送到 recipient
,转发所有可用的 gas 并在出错时恢复。
EIP1884 增加了某些操作码的 gas 成本,可能会使合约超过 transfer
施加的 2300 gas 限制,从而使它们无法通过 transfer
接收资金。sendValue
消除了此限制。
了解更多。
因为控制权已转移到 recipient ,因此必须小心不要创建重入漏洞。考虑使用 ReentrancyGuard 或 checks-effects-interactions 模式。 |
functionCall(address target, bytes data) → bytes
内部函数使用底层 call
执行 Solidity 函数调用。plain`call` 是函数调用的不安全替代方案:请改用此函数。
如果 target
恢复并带有恢复原因,则此函数会将其弹出(类似于常规的 Solidity 函数调用)。
返回原始返回的数据。要转换为预期的返回值,请使用 abi.decode
。
要求:
target
必须是合约。
使用 data
调用 target
不得恢复。
自 v3.1 起可用。
functionCall(address target, bytes data, string errorMessage) → bytes
内部函数与 functionCall
相同,但 errorMessage
作为 target
恢复时的回退恢复原因。
自 v3.1 起可用。
functionCallWithValue(address target, bytes data, uint256 value) → bytes
内部函数与 functionCall
相同,但也向 target
转移 value
wei。
要求:
调用合约必须具有至少 value
的 ETH 余额。
调用的 Solidity 函数必须是 payable
。
自 v3.1 起可用。
functionCallWithValue(address target, bytes data, uint256 value, string errorMessage) → bytes
内部函数与 functionCallWithValue
相同,但 errorMessage
作为 target
恢复时的回退恢复原因。
自 v3.1 起可用。
functionStaticCall(address target, bytes data) → bytes
内部函数与 functionCall
相同,但执行静态调用。
自 v3.3 起可用。
functionStaticCall(address target, bytes data, string errorMessage) → bytes
内部函数与 functionCall
相同,但执行静态调用。
自 v3.3 起可用。
functionDelegateCall(address target, bytes data) → bytes
内部函数与 functionCall
相同,但执行委托调用。
自 v3.4 起可用。
functionDelegateCall(address target, bytes data, string errorMessage) → bytes
内部函数与 functionCall
相同,但执行委托调用。
自 v3.4 起可用。
Arrays
与数组类型相关的函数的集合。
函数
findUpperBound(uint256[] array, uint256 element) → uint256
内部函数搜索已排序的 array
并返回包含大于或等于 element
的值的第一个索引。如果不存在此类索引(即,数组中的所有值都严格小于 element
),则返回数组长度。时间复杂度 O(log n)。
array
预计按升序排序,且不包含重复元素。
Counters
提供只能递增或递减 1 的计数器。这可以用于例如跟踪映射中的元素数量、颁发 ERC721 id 或计数请求 id。
包含 using Counters for Counters.Counter;
由于不可能通过递增 1 使 256 位整数溢出,因此 increment
可以跳过 SafeMath
溢出检查,从而节省 gas。但这确实假设了正确的使用,即永远不会直接访问底层的 _value
。
函数
current(struct Counters.Counter counter) → uint256
内部函数increment(struct Counters.Counter counter)
内部函数decrement(struct Counters.Counter counter)
内部函数Create2
帮助程序,使 CREATE2
EVM 操作码的使用更容易、更安全。
CREATE2
可用于提前计算智能合约的部署地址,从而实现有趣的新机制,称为“反事实交互”。
有关更多信息,请参见 EIP。
函数
deploy(uint256 amount, bytes32 salt, bytes bytecode) → address
内部函数使用 CREATE2
部署合约。可以通过 computeAddress
提前知道合约的部署地址。
合约的字节码可以从 Solidity 中通过 type(contractName).creationCode
获得。
要求:
bytecode
不得为空。
salt
必须尚未被用于 bytecode
。
工厂必须具有至少 amount
的余额。
如果 amount
为非零值,则 bytecode
必须具有 payable
构造函数。
computeAddress(bytes32 salt, bytes32 bytecodeHash) → address
内部函数返回如果通过 deploy
部署合约,该合约将存储的地址。bytecodeHash
或 salt
的任何更改都将导致新的目标地址。
computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) → address
内部函数返回如果从位于 deployer
的合约通过 deploy
部署合约,该合约将存储的地址。如果 deployer
是此合约的地址,则返回与 computeAddress
相同的值。
EnumerableMap
用于管理 Solidity 的可枚举变体的库
mapping
类型。
映射具有以下属性:
条目的添加、删除和存在检查以恒定时间 (O(1)) 完成。
条目的枚举以 O(n) 完成。不保证排序。
contract Example {
// 添加库方法
using EnumerableMap for EnumerableMap.UintToAddressMap;
// 声明一个集合状态变量
EnumerableMap.UintToAddressMap private myMap;
}
从 v3.0.0 开始,仅支持 uint256 → address
( UintToAddressMap
) 类型的映射。
函数
set(struct EnumerableMap.UintToAddressMap map, uint256 key, address value) → bool
内部函数向映射添加键值对,或更新现有键的值。O(1)。
如果键已添加到映射,即它尚未存在,则返回 true。
remove(struct EnumerableMap.UintToAddressMap map, uint256 key) → bool
内部函数从集合中删除一个值。O(1)。
如果键已从映射中删除,即它存在,则返回 true。
contains(struct EnumerableMap.UintToAddressMap map, uint256 key) → bool
内部函数如果键在映射中,则返回 true。O(1)。
length(struct EnumerableMap.UintToAddressMap map) → uint256
内部函数返回映射中的元素数。O(1)。
at(struct EnumerableMap.UintToAddressMap map, uint256 index) → uint256, address
内部函数返回存储在集合中位置 index
处的元素。O(1)。
请注意,不保证数组内值的排序,并且当添加或删除更多值时,它可能会更改。
要求:
index
必须严格小于 length
。tryGet(struct EnumerableMap.UintToAddressMap map, uint256 key) → bool, address
内部函数尝试返回与 key
关联的值。O(1)。
如果 key
不在映射中,则不会恢复。
自 v3.4 起可用。
get(struct EnumerableMap.UintToAddressMap map, uint256 key) → address
内部函数返回与 key
关联的值。O(1)。
要求:
key
必须在映射中。get(struct EnumerableMap.UintToAddressMap map, uint256 key, string errorMessage) → address
内部函数与 get
相同,当 key
不在映射中时,使用自定义错误消息。
此函数已弃用,因为它需要不必要地为错误消息分配内存。对于自定义恢复原因,请使用 tryGet 。 |
EnumerableSet
用于管理原始类型的集合的库。
集合具有以下属性:
元素的添加、删除和存在检查以恒定时间 (O(1)) 完成。
元素的枚举以 O(n) 完成。不保证排序。
contract Example {
// 添加库方法
using EnumerableSet for EnumerableSet.AddressSet;
// 声明一个集合状态变量
EnumerableSet.AddressSet private mySet;
}
截至 v3.3.0,支持 bytes32
( Bytes32Set
)、address
( AddressSet
) 和 uint256
( UintSet
) 类型的集合。
函数
add(struct EnumerableSet.Bytes32Set set, bytes32 value) → bool
内部函数将一个值添加到一个集合中。O(1)。
如果该值已添加到集合中,即它尚未存在,则返回 true。
remove(struct EnumerableSet.Bytes32Set set, bytes32 value) → bool
内部函数从集合中删除一个值。O(1)。
如果该值已从集合中删除,即它存在,则返回 true。
contains(struct EnumerableSet.Bytes32Set set, bytes32 value) → bool
内部函数如果该值在集合中,则返回 true。O(1)。
length(struct EnumerableSet.Bytes32Set set) → uint256
内部函数返回集合中的值的数量。O(1)。
at(struct EnumerableSet.Bytes32Set set, uint256 index) → bytes32
内部函数返回存储在集合中位置 index
处的值。O(1)。
请注意,不保证数组内值的排序,并且当添加或删除更多值时,它可能会更改。
要求:
index
必须严格小于 length
。add(struct EnumerableSet.AddressSet set, address value) → bool
内部函数将一个值添加到一个集合中。O(1)。
如果该值已添加到集合中,即它尚未存在,则返回 true。
remove(struct EnumerableSet.AddressSet set, address value) → bool
内部函数从集合中删除一个值。O(1)。
如果该值已从集合中删除,即它存在,则返回 true。
contains(struct EnumerableSet.AddressSet set, address value) → bool
内部函数如果该值在集合中,则返回 true。O(1)。
length(struct EnumerableSet.AddressSet set) → uint256
内部函数返回集合中的值的数量。O(1)。
at(struct EnumerableSet.AddressSet set, uint256 index) → address
内部函数返回存储在集合中位置 index
处的值。O(1)。
请注意,不保证数组内值的排序,并且当添加或删除更多值时,它可能会更改。
要求:
index
必须严格小于 length
。add(struct EnumerableSet.UintSet set, uint256 value) → bool
内部函数将一个值添加到一个集合中。O(1)。
如果该值已添加到集合中,即它尚未存在,则返回 true。
remove(struct EnumerableSet.UintSet set, uint256 value) → bool
内部函数从集合中删除一个值。O(1)。
如果该值已从集合中删除,即它存在,则返回 true。
contains(struct EnumerableSet.UintSet set, uint256 value) → bool
内部函数如果该值在集合中,则返回 true。O(1)。
length(struct EnumerableSet.UintSet set) → uint256
内部函数返回集合上的值的数量。O(1)。
at(struct EnumerableSet.UintSet set, uint256 index) → uint256
内部函数返回存储在集合中位置 index
处的值。O(1)。
请注意,不保证数组内值的排序,并且当添加或删除更多值时,它可能会更改。
要求:
index
必须严格小于 length
。SafeCast
带有添加的溢出检查的 Solidity 的 uintXX/intXX 强制转换运算符的包装器。
在 Solidity 中,从 uint256/int256 向下转换不会在溢出时恢复。这很容易导致不需要的利用或错误,因为开发人员通常假设溢出会引发错误。SafeCast
通过在此类操作溢出时恢复事务来恢复这种直觉。
使用此库而不是未检查的操作可以消除一整类错误,因此建议始终使用它。
可以与 SafeMath
和 SignedSafeMath
组合以将其扩展到更小的类型,方法是在 uint256
和 int256
上执行所有数学运算,然后向下转换。
函数
toUint128(uint256 value) → uint128
内部函数从 uint256 返回向下转换的 uint128,在溢出时- 输入必须符合 32 位
toUint16(uint256 value) → uint16
internal从 uint256 返回降转型后的 uint16,在溢出时恢复(当输入大于最大的 uint16 时)。
对应于 Solidity 的 uint16
运算符。
要求:
toUint8(uint256 value) → uint8
internal从 uint256 返回降转型后的 uint8,在溢出时恢复(当输入大于最大的 uint8 时)。
对应于 Solidity 的 uint8
运算符。
要求:
toUint256(int256 value) → uint256
internal将有符号 int256 转换为无符号 uint256。
要求:
toInt128(int256 value) → int128
internal从 int256 返回降转型后的 int128,在溢出时恢复(当输入小于最小的 int128 或大于最大的 int128 时)。
对应于 Solidity 的 int128
运算符。
要求:
可用版本:v3.1
toInt64(int256 value) → int64
internal从 int256 返回降转型后的 int64,在溢出时恢复(当输入小于最小的 int64 或大于最大的 int64 时)。
对应于 Solidity 的 int64
运算符。
要求:
可用版本:v3.1
toInt32(int256 value) → int32
internal从 int256 返回降转型后的 int32,在溢出时恢复(当输入小于最小的 int32 或大于最大的 int32 时)。
对应于 Solidity 的 int32
运算符。
要求:
可用版本:v3.1
toInt16(int256 value) → int16
internal从 int256 返回降转型后的 int16,在溢出时恢复(当输入小于最小的 int16 或大于最大的 int16 时)。
对应于 Solidity 的 int16
运算符。
要求:
可用版本:v3.1
toInt8(int256 value) → int8
internal从 int256 返回降转型后的 int8,在溢出时恢复(当输入小于最小的 int8 或大于最大的 int8 时)。
对应于 Solidity 的 int8
运算符。
要求:
可用版本:v3.1
toInt256(uint256 value) → int256
internal将无符号 uint256 转换为有符号 int256。
要求:
Strings
字符串操作。
函数
toString(uint256 value) → string
internal将 uint256
转换为其 ASCII string
表示形式。
- 原文链接: docs.openzeppelin.com/co...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!