本文档介绍了 OpenZeppelin Contracts 库中与 ERC721 非同质化代币标准相关的接口、合约和实用程序。
你没有在阅读当前版本的文档。5.x是当前版本。
最好在https://docs.openzeppelin.com/contracts/api/token/erc721 上查看本文档 |
这组接口、合约和实用程序都与ERC721 非同质化代币标准有关。
有关如何创建 ERC721 代币的演练,请阅读我们的 ERC721 指南。 |
EIP 指定了四个接口:
IERC721
:所有兼容实现中所需的核心功能。
IERC721Metadata
:可选扩展,增加了名称、符号和代币 URI,几乎总是包含在内。
IERC721Enumerable
:可选扩展,允许在链上枚举代币,通常不包含,因为它需要大量的 gas 开销。
IERC721Receiver
:如果合约想要通过 safeTransferFrom
接受代币,则必须由合约实现的接口。
OpenZeppelin 合约提供了所有四个接口的实现:
ERC721
:核心和元数据扩展,带有基本 URI 机制。
ERC721Enumerable
:可枚举扩展。
ERC721Holder
:接收器接口的简单实现。
此外,还有一些其他的扩展:
ERC721Consecutive
:ERC2309 的一个实现,用于在构造期间按照 ERC721 铸造批量的代币。
ERC721URIStorage
:一种更灵活但更昂贵的存储元数据的方式。
ERC721Votes
:支持投票和投票委托。
ERC721Royalty
:按照 ERC2981 发出特许权使用费信息的一种方式。
ERC721Pausable
:暂停合约操作的原语。
ERC721Burnable
:代币持有者销毁自己的代币的一种方式。
ERC721Wrapper
:包装器,用于创建由另一个 ERC721 支持的 ERC721,带有存款和取款方法。与 ERC721Votes
结合使用非常有用。
这组核心合约旨在保持公正,允许开发人员访问 ERC721 中的内部函数(例如 _mint ),并以他们喜欢的方式将其公开为外部函数。另一方面,ERC721 预设(例如 ERC721PresetMinterPauserAutoId )的设计使用了公正的模式,以为开发人员提供随时可用、可部署的合约。 |
IERC721
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
符合 ERC721 标准的合约的必需接口。
函数
IERC165
事件
balanceOf(address owner) → uint256 balance
external返回 owner
账户中的代币数量。
ownerOf(uint256 tokenId) → address owner
external返回 tokenId
代币的所有者。
要求:
tokenId
必须存在。safeTransferFrom(address from, address to, uint256 tokenId, bytes data)
external将 tokenId
代币从 from
安全地转移到 to
。
要求:
from
不能是零地址。
to
不能是零地址。
tokenId
代币必须存在并且归 from
所有。
如果调用者不是 from
,则必须通过 approve
或 setApprovalForAll
批准移动此代币。
如果 to
指的是智能合约,则它必须实现 IERC721Receiver.onERC721Received
,该合约在安全转移时被调用。
发出 Transfer
事件。
safeTransferFrom(address from, address to, uint256 tokenId)
external将 tokenId
代币从 from
安全地转移到 to
,首先检查合约接收者是否知道 ERC721 协议,以防止代币被永久锁定。
要求:
from
不能是零地址。
to
不能是零地址。
tokenId
代币必须存在并且归 from
所有。
如果调用者不是 from
,则必须已通过 approve
或 setApprovalForAll
允许移动此代币。
如果 to
指的是智能合约,则它必须实现 IERC721Receiver.onERC721Received
,该合约在安全转移时被调用。
发出 Transfer
事件。
transferFrom(address from, address to, uint256 tokenId)
external将 tokenId
代币从 from
转移到 to
。
请注意,调用者有责任确认接收者能够接收 ERC721<br>否则它们可能会永久丢失。使用 safeTransferFrom 可以防止丢失,但调用者必须<br>了解这增加了一个外部调用,可能会导致重入漏洞。 |
要求:
from
不能是零地址。
to
不能是零地址。
tokenId
代币必须归 from
所有。
如果调用者不是 from
,则必须通过 approve
或 setApprovalForAll
批准移动此代币。
发出 Transfer
事件。
approve(address to, uint256 tokenId)
external授予 to
将 tokenId
代币转账到另一个账户的权限。
当代币被转移时,批准将被清除。
一次只能批准一个账户,因此批准零地址会清除之前的批准。
要求:
调用者必须拥有该代币或成为已批准的 Operator。
tokenId
必须存在。
发出 Approval
事件。
setApprovalForAll(address operator, bool approved)
external批准或删除 operator
作为调用者的 Operator。
Operator 可以为调用者拥有的任何代币调用 transferFrom
或 safeTransferFrom
。
要求:
operator
不能是调用者。发出 ApprovalForAll
事件。
getApproved(uint256 tokenId) → address operator
external返回为 tokenId
代币批准的账户。
要求:
tokenId
必须存在。isApprovedForAll(address owner, address operator) → bool
external返回是否允许 operator
管理 owner
的所有资产。
Transfer(address indexed from, address indexed to, uint256 indexed tokenId)
event当 tokenId
代币从 from
转移到 to
时发出。
Approval(address indexed owner, address indexed approved, uint256 indexed tokenId)
event当 owner
允许 approved
管理 tokenId
代币时发出。
ApprovalForAll(address indexed owner, address indexed operator, bool approved)
event当 owner
允许或禁用(approved
)operator
管理其所有资产时发出。
IERC721Metadata
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
参见 https://eips.ethereum.org/EIPS/eip-721
函数
IERC721
IERC165
事件
IERC721
name() → string
external返回代币集合名称。
symbol() → string
external返回代币集合符号。
tokenURI(uint256 tokenId) → string
external返回 tokenId
代币的统一资源标识符 (URI)。
IERC721Enumerable
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
参见 https://eips.ethereum.org/EIPS/eip-721
函数
IERC721
IERC165
事件
IERC721
totalSupply() → uint256
external返回合约存储的代币总数。
tokenOfOwnerByIndex(address owner, uint256 index) → uint256
external返回 owner
在其代币列表的给定 index
处拥有的代币 ID。
与 balanceOf
一起使用以枚举 owner
的所有代币。
tokenByIndex(uint256 index) → uint256
external返回合约存储的所有代币的给定 index
处的代币 ID。
与 totalSupply
一起使用以枚举所有代币。
ERC721
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
ERC721 非同质化代币标准的实现,包括元数据扩展,但不包括可枚举扩展,该扩展可作为单独的 ERC721Enumerable
提供。
函数
事件
IERC721
constructor(string name_, string symbol_)
public通过为代币集合设置 加粗name加粗 和 加粗symbol加粗 来初始化合约。
supportsInterface(bytes4 interfaceId) → bool
publicbalanceOf(address owner) → uint256
publicownerOf(uint256 tokenId) → address
public参见 IERC721.ownerOf
。
name() → string
publicsymbol() → string
publictokenURI(uint256 tokenId) → string
public_baseURI() → string
internal用于计算 tokenURI
的基本 URI。如果设置,每个代币的结果 URI 将是 加粗baseURI加粗 和 加粗tokenId加粗 的串联。默认为空,可以在子合约中覆盖。
approve(address to, uint256 tokenId)
public参见 IERC721.approve
。
getApproved(uint256 tokenId) → address
publicsetApprovalForAll(address operator, bool approved)
publicisApprovedForAll(address owner, address operator) → bool
publictransferFrom(address from, address to, uint256 tokenId)
publicsafeTransferFrom(address from, address to, uint256 tokenId)
publicsafeTransferFrom(address from, address to,#####
_afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize)` internal在任何 token 转移之后调用的Hook。这包括铸造和销毁。如果使用了ERC721Consecutive
,则Hook可能会被调用作为连续(批量)铸造的一部分,如 batchSize
大于 1 所指示的那样。
调用条件:
当 from
和 to
都不是零时,from
的 token 被转移到 to
。
当 from
是零时,token 为 to
铸造。
当 to
是零时,from
的 token 被销毁。
from
和 to
永远不会都为零。
batchSize
非零。
要了解有关Hook的更多信息,请访问 使用Hook。
__unsafe_increaseBalance(address account, uint256 amount)
internal对余额的不安全写入访问,由使用 ownerOf
覆盖来“铸造”token的扩展使用。
任何调用此方法的人都必须确保余额与所有权保持一致。 不变的是,对于任何地址 a ,balanceOf(a) 返回的值必须等于 token 的数量,<br>使得 ownerOf(tokenId) 是 a 。 |
ERC721Enumerable
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
这实现了 EIP 中定义的 ERC721
的一个可选扩展,它添加了对合约中所有 token id 以及每个账户拥有的所有 token id 的可枚举性。
函数
ERC721
事件
IERC721
supportsInterface(bytes4 interfaceId) → bool
publictokenOfOwnerByIndex(address owner, uint256 index) → uint256
public请参阅IERC721Enumerable.tokenOfOwnerByIndex
。
totalSupply() → uint256
public请参阅IERC721Enumerable.totalSupply
。
tokenByIndex(uint256 index) → uint256
public请参阅IERC721Enumerable.tokenByIndex
。
_beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize)
internal参见 ERC721._beforeTokenTransfer
。
IERC721Receiver
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
任何想要支持来自 ERC721 资产合约的 safeTransfers 的合约的接口。
函数
onERC721Received(address operator, address from, uint256 tokenId, bytes data) → bytes4
external每当一个 IERC721
tokenId
token 通过 operator
从 from
经由 IERC721.safeTransferFrom
转移到此合约时,此函数被调用。
它必须返回其 Solidity selector 以确认 token 转移。 如果返回任何其他值或接收者未实现该接口,则转移将被回退。
该 selector 可以在 Solidity 中使用 IERC721Receiver.onERC721Received.selector
获得。
ERC721Pausable
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol";
具有可暂停 token 转移、铸造和销毁的 ERC721 token。
适用于诸如在评估期结束前阻止交易,或者在发生重大错误时使用紧急开关冻结所有 token 转移等情况。
此合约不包括公共的暂停和取消暂停函数。除了继承此合约之外,你还必须定义这两个函数,调用<br>Pausable._pause 和 Pausable._unpause 内部函数,并具有适当的<br>访问控制,例如使用 AccessControl 或 Ownable 。不这样做将<br>使合约无法暂停。 |
函数
Pausable
ERC721
事件
Pausable
IERC721
_beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize)
internal参见 ERC721._beforeTokenTransfer
。
要求:
ERC721Burnable
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
可以被销毁(销毁)的 ERC721 Token。
函数
ERC721
事件
IERC721
burn(uint256 tokenId)
public销毁 tokenId
。参见 ERC721._burn
.
要求:
tokenId
或成为批准的操作员。ERC721Consecutive
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Consecutive.sol";
实现EIP-2309中定义的 ERC2309"连续传输扩展"。
此扩展允许仅在合约构造期间大量批量铸造 token。对于可升级的 合约,这意味着批量铸造仅在代理部署期间可用,而不在后续升级中可用。 默认情况下,这些批次一次最多限制为 5000 个 token,以适应链下索引器。
使用此扩展会删除在合约构造期间铸造单个 token 的能力。此功能在构造后重新获得。在构造期间,仅允许批量铸造。
此扩展绕过了为批量铸造的 token 提供的Hook _beforeTokenTransfer 和 _afterTokenTransfer 。 当使用此扩展时,除了_beforeTokenTransfer 和 _afterTokenTransfer 之外,还应考虑 {_beforeConsecutiveTokenTransfer} 和 {_afterConsecutiveTokenTransfer} Hook。 |
当覆盖 _afterTokenTransfer 时,请注意调用顺序。 如果在调用super之前未先调用 ownerOf ,则 ownerOf 在 _afterTokenTransfer 执行期间可能会返回无效值。为了安全起见,请在自定义逻辑之前执行super调用。 |
自 v4.8 起可用。
函数
ERC721
[approve(to, tokenId)
](https://docs.openzeppelin.com/contracts/4.x/api/token/erc721#ERC721-approve-参见 ERC721._afterTokenTransfer
。对顺序铸造的 token 的销毁必须是显式的。
ERC721URIStorage
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
具有基于存储的 token URI 管理的 ERC721 token。
函数
ERC721
事件
IERC4906
IERC721
supportsInterface(bytes4 interfaceId) → bool
publictokenURI(uint256 tokenId) → string
public_setTokenURI(uint256 tokenId, string _tokenURI)
internal将 _tokenURI
设置为 tokenId
的 tokenURI。
触发 {MetadataUpdate}。
要求:
tokenId
必须存在。_burn(uint256 tokenId)
internal参见 ERC721._burn
。此重载还会检查是否为 token 设置了特定的 URI,如果是,则从存储映射中删除 token URI。
ERC721Votes
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Votes.sol";
ERC721 的扩展,用于支持由 Votes
实现的投票和委托,其中每个单独的 NFT 计为 1 个投票单位。
在 token 被委托之前,它们不计为投票,因为必须跟踪投票,这会在每次转移时产生额外的成本。Token 持有者可以委托给受信任的代表,由该代表决定如何在治理决策中利用投票,或者他们可以委托给自己,成为自己的代表。
自 v4.5 起可用。
函数
投票
EIP712
ERC721
事件
IVotes
IERC5267
IERC721
_afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize)
internal参见 ERC721._afterTokenTransfer
。当 token 被转移时调整投票。
触发 IVotes.DelegateVotesChanged
事件。
_getVotingUnits(address account) → uint256
internal返回 account
的余额。
重写此函数可能会导致不正确的投票跟踪。 |
ERC721Royalty
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Royalty.sol";
ERC721 的扩展,具有 ERC2981 NFT 版税标准,这是一种检索版税支付信息的标准化方法。
可以通过 ERC2981._setDefaultRoyalty
为所有 token id 全局指定版税信息,和/或通过 ERC2981._setTokenRoyalty
为特定 token id 单独指定版税信息 。后者优先于前者。
ERC-2981 仅指定了一种传递版税信息的方式,并不强制执行其支付。 请参阅<br>Rationale 在 EIP 中。 市场预计会<br>自愿支付销售版税,但请注意,此标准尚未得到广泛支持。 |
自 v4.5 起可用。
函数
ERC721
ERC2981
事件
IERC721
supportsInterface(bytes4 interfaceId) → bool
public_burn(uint256 tokenId)
internal参见 ERC721._burn
。此重载还会清除 token 的版税信息。
ERC721Wrapper
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Wrapper.sol";
为支持 token 包装而对 ERC721 token 合约进行的扩展。
用户可以存入和提取“底层 token”,并接收具有匹配 tokenId 的“包装 token”。这与其他模块结合使用很有用。例如,将此包装机制与 ERC721Votes
结合使用,可以将现有的“基本”ERC721 包装成治理 token。
自 v4.9.0 起可用
函数
ERC721
[setApprovalForAll(operator, approved)
](https://- _baseURI()
Pausable
ERC721Burnable
ERC721Enumerable
ERC721
AccessControlEnumerable
AccessControl
Events
Pausable
IERC721
IAccessControl
constructor(string name, string symbol, string baseTokenURI)
public授予 DEFAULT_ADMIN_ROLE
、MINTER_ROLE
和 PAUSER_ROLE
给部署合约的账户。
Token URI 将基于 baseURI
和它们的 token ID 自动生成。
参见 ERC721.tokenURI
。
_baseURI() → string
internal用于计算 tokenURI
的基础 URI。如果设置,每个
token 的结果 URI 将是 baseURI
和 tokenId
的串联。默认为空,可以在子合约中覆盖。
mint(address to)
public为 to
创建一个新 token。它的 token ID 将被自动分配(并且可以在发出的 IERC721.Transfer
事件中获得),并且 token
URI 将根据构造时传递的 base URI 自动生成。
参见 ERC721._mint
。
要求:
MINTER_ROLE
。pause()
public暂停所有 token 的转移。
参见 ERC721Pausable
和 Pausable._pause
。
要求:
PAUSER_ROLE
。unpause()
public取消暂停所有 token 的转移。
参见 ERC721Pausable
和 Pausable._unpause
。
要求:
PAUSER_ROLE
。_beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize)
internalsupportsInterface(bytes4 interfaceId) → bool
publicERC721Holder
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
IERC721Receiver
接口的实现。
接受所有 token 转移。
确保合约能够使用 IERC721.safeTransferFrom
、IERC721.approve
或 IERC721.setApprovalForAll
来使用它的 token。
Functions
onERC721Received(address, address, uint256, bytes) → bytes4
public参见 IERC721Receiver.onERC721Received
。
总是返回 IERC721Receiver.onERC721Received.selector
。
- 原文链接: docs.openzeppelin.com/co...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!