本文档介绍了 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)的设计使用了公正的模式,以为开发人员提供随时可用、可部署的合约。 | 
IERC721import "@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 管理其所有资产时发出。
IERC721Metadataimport "@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)。
IERC721Enumerableimport "@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 一起使用以枚举所有代币。
ERC721import "@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。 | 
ERC721Enumerableimport "@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。
IERC721Receiverimport "@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 获得。
ERC721Pausableimport "@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。
要求:
ERC721Burnableimport "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";可以被销毁(销毁)的 ERC721 Token。
函数
ERC721
事件
IERC721
burn(uint256 tokenId) public销毁 tokenId。参见 ERC721._burn.
要求:
tokenId 或成为批准的操作员。ERC721Consecutiveimport "@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 的销毁必须是显式的。
ERC721URIStorageimport "@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。
ERC721Votesimport "@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 的余额。
| 重写此函数可能会导致不正确的投票跟踪。 | 
ERC721Royaltyimport "@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 的版税信息。
ERC721Wrapperimport "@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 publicERC721Holderimport "@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 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
 
                如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!