ERC721

此模块提供与 ERC721 合约相关的接口、预设和实用程序。

提示:有关 ERC721 的概述,请阅读我们的 ERC721 指南

核心

IERC721

use openzeppelin_token::erc721::interface::IERC721;

EIP721 中定义的 IERC721 标准的接口。

0x33eb2f84c309543403fd69f0d0f363781ef06ef6faeb0131ff16ea3175bd943

函数

balance_of(account: ContractAddress) → u256 external

返回 account 拥有的 NFT 数量。

owner_of(token_id: u256) → ContractAddress external

返回 token_id 的所有者地址。

safe_transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256, data: Span<felt252>) external

token_id 的所有权从 from 转移到 to,首先检查 to 是否知道 ERC721 协议,以防止 Token 永远被锁定。 有关合约如何传递它们对 ERC721 协议的了解的信息,请参阅 接收 Token

发出一个 Transfer 事件。

transfer_from(from: ContractAddress, to: ContractAddress, token_id: u256) external

token_id 的所有权从 from 转移到 to

请注意,调用者有责任确认接收者有能力接收 ERC721 转移,否则它们可能会永久丢失。 使用 IERC721::safe_transfer_from 可以防止token丢失,但调用者必须理解这会增加一个外部调用,可能会产生重入漏洞。

发出一个 Transfer 事件。

approve(to: ContractAddress, token_id: u256) external

更改或重申 NFT 的批准地址。

发出一个 Approval 事件。

set_approval_for_all(operator: ContractAddress, approved: bool) external

启用或禁用对 operator 的授权,以管理调用者的所有资产。

发出一个 ApprovalForAll 事件。

get_approved(token_id: u256) -> u256 external

返回 token_id 的批准地址。

is_approved_for_all(owner: ContractAddress, operator: ContractAddress) -> bool external

查询 operator 是否为 owner 的授权operator。

事件

Approval(owner: ContractAddress, approved: ContractAddress, token_id: u256) event

owner 启用 approved 以管理 token_id Token时发出。

ApprovalForAll(owner: ContractAddress, operator: ContractAddress, approved: bool) event

owner 启用或禁用 operator 以管理 token_id Token时发出。

Transfer(from: ContractAddress, to: ContractAddress, token_id: u256) event

token_id Token从 from 转移到 `to`时发出。

IERC721Metadata

use openzeppelin_token::erc721::interface::IERC721Metadata;

EIP721 中可选元数据函数的接口。

0xabbcd595a567dce909050a1038e055daccb3c42af06f0add544fa90ee91f25

函数

name() -> ByteArray external

返回 NFT 名称。

symbol() -> ByteArray external

返回 NFT ticker 符号。

token_uri(token_id: u256) -> ByteArray external

返回 token_id Token的 Uniform Resource Identifier (URI)。 如果未为 token_id 设置 URI,则返回值将为空 ByteArray

ERC721Component

use openzeppelin_token::erc721::ERC721Component;

实现了 IERC721IERC721Metadata 的 ERC721 组件。

注意:实施 SRC5Component 是本组件需要实现的要求。

注意:请参阅 Hooks 以了解 Hook 的使用方式。

Hooks

Hooks 是一些函数,其实现可以扩展组件源代码的功能。每个 使用 ERC721Component 的合约都应提供 ERC721HooksTrait 的实现。对于基本 Token合约, 必须提供没有逻辑的空实现。

提示:您可以使用 openzeppelin_token::erc721::ERC721HooksEmptyImpl,它已作为库的一部分提供 为此目的。

before_update(ref self: ContractState, to: ContractAddress, token_id: u256, auth: ContractAddress) hook

update 函数的开头,在任何其他逻辑之前执行的函数。

after_update(ref self: ContractState, to: ContractAddress, token_id: u256, auth: ContractAddress) hook

update 函数末尾执行的函数。

可嵌入的函数

balance_of(self: @ContractState, account: ContractAddress) → u256 external

请参阅 IERC721::balance_of

owner_of(self: @ContractState, token_id: u256) → ContractAddress external

请参阅 IERC721::owner_of

要求:

  • token_id 存在。

safe_transfer_from(ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256, data: Span<felt252>) external

要求:

  • 调用者要么获得批准,要么是 token_id 的所有者。

  • to 不是零地址。

  • from 不是零地址。

  • token_id 存在。

  • to 要么是账户合约,要么支持 IERC721Receiver 接口。

transfer_from(ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256) external

请参阅 IERC721::transfer_from

要求:

  • 调用者要么获得批准,要么是 token_id 的所有者。

  • to 不是零地址。

  • from 不是零地址。

  • token_id 存在。

approve(ref self: ContractState, to: ContractAddress, token_id: u256) external

请参阅 IERC721::approve

要求:

  • 调用者要么是被批准的operator,要么是 token_id 的所有者。

  • to 不能是 Token所有者或零地址。

  • token_id 存在。

set_approval_for_all(ref self: ContractState, operator: ContractAddress, approved: bool) external

要求:

  • operator 不是零地址。

get_approved(self: @ContractState, token_id: u256) -> u256 external

请参阅 IERC721::get_approved

要求:

  • token_id 存在。

is_approved_for_all(self: @ContractState, owner: ContractAddress, operator: ContractAddress) -> bool external

name(self: @ContractState) -> ByteArray external

请参阅 IERC721Metadata::name

symbol(self: @ContractState) -> ByteArray external

token_uri(self: @ContractState, token_id: u256) -> ByteArray external

返回 token_id Token的 Uniform Resource Identifier (URI)。 如果设置了基本 URI,则每个 Token 的结果 URI 将是基本 URI 和 Token ID 的串联。 例如,基本 URI https://token-cdn-domain/ 将作为 https://token-cdn-domain/123 返回 Token ID 123

如果未为 token_id 设置 URI,则返回值将为空 ByteArray

balanceOf(self: @ContractState, account: ContractAddress) -> u256 external

ownerOf(self: @ContractState, tokenId: u256) -> ContractAddress external

safeTransferFrom(ref self: ContractState, from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span<felt252>) external

transferFrom(ref self: ContractState, from: ContractAddress, to: ContractAddress, tokenId: u256) external

setApprovalForAll(ref self: ContractState, operator: ContractAddress, approved: bool) external

getApproved(self: @ContractState, tokenId: u256) -> ContractAddress external

isApprovedForAll(self: @ContractState, owner: ContractAddress, operator: ContractAddress) -> bool external

tokenURI(self: @ContractState, tokenId: u256) -> ByteArray external

内部函数

initializer(ref self: ContractState, name: ByteArray, symbol: ByteArray, base_uri: ByteArray) internal

通过设置 Token名称和符号来初始化合约。 这应该在合约的构造函数中使用。

警告:大多数 ERC721 合约都公开了 IERC721Metadata 接口, 这就是此初始化程序旨在支持的。 如果合约未公开 IERC721Metadata 接口, 意味着该 Token没有名称、符号或 URI, 则合约必须改用 initializer_no_metadata 在构造函数中。 不遵守这些说明可能会导致意外问题,尤其是在 用户界面。

initializer_no_metadata(ref self: ContractState) internal

通过仅注册 IERC721 接口来初始化没有元数据的合约。

警告:此初始化程序应仅在非常特殊的情况下在构造期间使用,即合约未公开 IERC721Metadata 接口。 使用此初始化程序初始化合约意味着 Token将没有名称、符号或 URI。

exists(self: @ContractState, token_id: u256) -> bool internal

返回 token_id 是否存在的内部函数。

Token在被铸造时开始存在(mint),并在被烧毁时停止存在(burn)。

transfer(ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256) internal

token_idfrom 转移到 to

没有访问限制的内部函数。

警告:如果 to 不知道 ERC721 协议,则此方法可能会导致 Token丢失。

要求:

  • to 不是零地址。

  • from 是 Token所有者。

  • token_id 存在。

发出一个 Transfer 事件。

mint(ref self: ContractState, to: ContractAddress, token_id: u256) internal

铸造 token_id 并将其转移到 to。 没有访问限制的内部函数。

警告:如果 to 不知道 ERC721 协议,则此方法可能会导致 Token丢失。

要求:

  • to 不是零地址。

  • token_id 不存在。

发出一个 Transfer 事件。

safe_transfer(ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256, data: Span<felt252>) internal

如果 to 是账户或 IERC721Receiver,则将 token_id 的所有权从 from 转移。

data 是附加数据,它没有指定的格式,并在 IERC721Receiver::on_erc721_received 中转发到 to

警告:此方法会向接收者合约发出外部调用,这可能导致重入漏洞。

要求:

  • to 不能是零地址。

  • from 必须是 Token所有者。

  • token_id 存在。

  • to 要么是账户合约,要么支持 IERC721Receiver 接口。

发出一个 Transfer 事件。

safe_mint(ref self: ContractState, to: ContractAddress, token_id: u256, data: Span<felt252>) internal

如果 to 是账户或 IERC721Receiver,则铸造 token_id

data 是附加数据,它没有指定的格式,并在 IERC721Receiver::on_erc721_received 中转发到 to

警告:此方法会向接收者合约发出外部调用,这可能导致重入漏洞。

要求:

  • token_id 不存在。

  • to 要么是账户合约,要么支持 IERC721Receiver 接口。

发出一个 Transfer 事件。

burn(ref self: ContractState, token_id: u256) internal

销毁 token_id。Token被烧毁时,批准被清除。

此内部函数不检查调用者是否被授权 操作 Token。

要求:

  • token_id 存在。

发出一个 Transfer 事件。

update(ref self: ContractState, to: ContractAddress, token_id: u256, auth: ContractAddress) internal

将其当前所有者转移到 token_idto,或者,如果当前所有者 (或 to)是零地址,则进行铸造(或销毁)。返回更新之前 token_id 的所有者。

auth 参数是可选的。如果传递的值为非零值,则此函数将检查 auth 是 Token的所有者,还是被批准操作 Token(由所有者)。

This function can be extended by using the ERC721HooksTrait to add functionality before and/or after transfer, mint, or burn.

发出一个 Transfer 事件。

注意:可以使用 ERC721HooksTrait 扩展功能,在转移、铸造或销毁前后添加功能。

_owner_of(self: @ContractState, token_id: felt252) -> ContractAddress internal

返回 token_id 的所有者地址的内部函数。

_require_owned(self: @ContractState, token_id: felt252) -> ContractAddress internal

如果所有者是零地址,则 <<ERC721Component-_owner_of[_owner_of] 会引发panic。

_approve(ref self: ContractState, to: ContractAddress, token_id: u256, auth: ContractAddress) internal

批准 to 以操作 `[.contract]

IERC721Receiver

use openzeppelin_token::erc721::interface::IERC721Receiver;

支持接收 safe_transfer_from transfers 的合约接口。

0x3a0dff5f70d80458ad14ae37bb182a728e3c8cdda0402a5daa86620bdf910bc

Functions

on_erc721_received(operator: ContractAddress, from: ContractAddress, token_id: u256, data: Span<felt252>) -> felt252 external

每当一个 IERC721 token_id token 通过 IERC721::safe_transfer_fromoperatorfrom 转移到这个非账户合约时,此函数被调用。

ERC721ReceiverComponent

use openzeppelin_token::erc721::ERC721ReceiverComponent;

实现 IERC721Receiver 的 ERC721Receiver 组件。

实施 SRC5Component 是本组件需要实现的要求。
Embeddable Implementations
Internal Functions
InternalImpl

Embeddable functions

on_erc721_received(self: @ContractState, operator: ContractAddress, from: ContractAddress, token_id: u256, data Span<felt252>) -> felt252 external

返回 IERC721Receiver 接口 ID。

onERC721Received(self: @ContractState, operator: ContractAddress, from: ContractAddress, token_id: u256, data Span<felt252>) -> felt252 external

Internal functions

initializer(ref self: ContractState) internal

注册 IERC721Receiver 接口 ID,使其可以通过内省(introspection)得到支持。

Extensions

IERC721Enumerable

EIP721 中可选的可枚举函数接口。

0x16bc0f502eeaf65ce0b3acb5eea656e2f26979ce6750e8502a82f377e538c87

Functions

total_supply() -> u256 external

返回合约存储的 token 总量。

token_by_index(index: u256) -> u256 external

返回合约存储的所有 token 中给定 index 处的 token id。 与 IERC721Enumerable::total_supply 一起使用可以枚举所有 token。

token_of_owner_by_index(owner: ContractAddress, index: u256) -> u256 external

返回 owner 拥有的 token 列表中给定 index 处的 token id。 与 IERC721::balance_of 一起使用可以枚举所有 owner 的 token。

ERC721EnumerableComponent

use openzeppelin_token::erc721::extensions::ERC721EnumerableComponent;

EIP 中定义的 ERC721 扩展,它增加了合约中所有 token id 以及每个账户拥有的所有 token id 的可枚举性。 此扩展允许合约发布其整个 NFT 列表并使其可被发现。

实现 ERC721Component 是实现此组件的先决条件。

为了正确跟踪 token id,此扩展要求在每次转移、铸造或销毁操作之前调用 ERC721EnumerableComponent::before_update 函数。 为此,必须使用 ERC721HooksTrait::before_update hook。 以下是如何在合约中实现 hook:

#[starknet::contract]
mod ERC721EnumerableContract {
    (...)

    component!(path: ERC721Component, storage: erc721, event: ERC721Event);
    component!(path: ERC721EnumerableComponent, storage: erc721_enumerable, event: ERC721EnumerableEvent);
    component!(path: SRC5Component, storage: src5, event: SRC5Event);

    impl ERC721HooksImpl of ERC721Component::ERC721HooksTrait<ContractState> {
        fn before_update(
            ref self: ERC721Component::ComponentState<ContractState>,
            to: ContractAddress,
            token_id: u256,
            auth: ContractAddress
        ) {
            let mut contract_state = self.get_contract_mut();
            contract_state.erc721_enumerable.before_update(to, token_id);
        }
    }
}

Embeddable functions

total_supply(self: @ContractState) → u256 external

返回 account 当前拥有的票数。

token_by_index(self: @ContractState, index: u256) → u256 external

要求:

  • index 小于 token 总供应量。

token_of_owner_by_index(self: @ContractState, owner: ContractAddress, index: u256) → u256 external

要求:

  • index 小于 owner 的 token 余额。

  • owner 不是零地址。

Internal functions

initializer(ref self: ContractState) internal

注册 IERC721Enumerable 接口 ID,使其可以通过内省得到支持。

before_update(ref self: ContractState, to: ContractAddress, token_id: u256) internal

更新所有权和 token 跟踪数据结构。

当 token 被铸造(或销毁)时,token_id 被添加到(或从)token 跟踪结构中。

当 token 被转移、铸造或销毁时,所有权跟踪数据结构会反映 token_id 所有权的变化。

这必须添加到实现合约的 ERC721HooksTrait::before_update hook 中。

all_tokens_of_owner(self: @ContractState, owner: ContractAddress) → Span<u256> internal

返回指定 owner 拥有的所有 token id 的列表。 此函数提供了比调用 ERC721::balance_of 并使用 ERC721Enumerable::token_of_owner_by_index 迭代 token 更有效的替代方案。

要求:

  • owner 不是零地址。

_add_token_to_owner_enumeration(ref self: ContractState, to: ContractAddress, token_id: u256) internal

将 token 添加到此扩展的所有权跟踪数据结构。

_add_token_to_all_tokens_enumeration(ref self: ContractState, token_id: u256) internal

将 token 添加到此扩展的 token 跟踪数据结构。

_remove_token_from_owner_enumeration(ref self: ContractState, from: ContractAddress, token_id: u256) internal

从此扩展的所有权跟踪数据结构中删除 token。

这具有 0(1) 的时间复杂度,但通过将 token_id 及其索引与最后一个 token id 及其索引交换来改变拥有的 token 的索引顺序,例如从 [1, 2, 3, 4] 中删除 1 会导致 [4, 2, 3]

_remove_token_from_all_tokens_enumeration(ref self: ContractState, token_id: u256) internal

从此扩展的 token 跟踪数据结构中删除 token_id

这具有 0(1) 的时间复杂度,但通过将 token_id 及其索引与最后一个 token id 及其索引交换来改变索引顺序,例如从 [1, 2, 3, 4] 中删除 1 会导致 [4, 2, 3]

Presets

ERC721Upgradeable

use openzeppelin_presets::ERC721Upgradeable;

利用 ERC721Component 的可升级 ERC721 合约。

0x06d1cd9d8c2008d36bd627e204c3e5f565d4e632de4e50b36d2388c7ba7a64ce

Embedded Implementations
ERC721MixinImpl
OwnableMixinImpl
External Functions

Constructor

constructor(ref self: ContractState, name: ByteArray, symbol: ByteArray, recipient: ContractAddress, token_ids: Span<u256>, base_uri: ByteArray, owner: ContractAddress) constructor

设置 namesymbol。 将 token_ids tokens 铸造给 recipient 并设置 base_uri。 将 owner 分配为具有升级权限的合约所有者。

External functions

upgrade(ref self: ContractState, new_class_hash: ClassHash) external

将合约升级到由 new_class_hash 给出的新实现。

要求:

  • 调用者是合约所有者。

  • new_class_hash 不能为零。