Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ERC721EnumerableComponent extension #983

Merged
merged 83 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
e5c5e5f
feat: working in logic
ericnordelo Apr 15, 2024
110d8f7
feat: add empty impl
ericnordelo Apr 23, 2024
4a7f8a5
Merge branch 'main' of github.com:OpenZeppelin/cairo-contracts into f…
ericnordelo Apr 23, 2024
d71ee92
feat: finish docs
ericnordelo Apr 23, 2024
d61e449
feat: update CHANGELOG
ericnordelo Apr 23, 2024
8e894ea
draft erc721 enum
andrew-fleming Apr 28, 2024
295530b
fix comp, start testing
andrew-fleming Apr 28, 2024
d5838d3
fix fmt
andrew-fleming Apr 28, 2024
b225343
fix fmt
andrew-fleming Apr 30, 2024
649c7c6
change fn name
andrew-fleming Apr 30, 2024
cff482a
add more tests for interface fns
andrew-fleming Apr 30, 2024
f76da3e
add in-code comments
andrew-fleming May 3, 2024
96f9d09
add more tests
andrew-fleming May 3, 2024
d9455ae
fix formatting
andrew-fleming May 3, 2024
73fbbc9
remove unused imports, clean up code
andrew-fleming May 3, 2024
5a128ca
remove space
andrew-fleming May 4, 2024
5987c8f
start erc721enum section
andrew-fleming May 4, 2024
0fcfc13
fix fn order
andrew-fleming May 5, 2024
fc27ae7
add in-code comments, fix fn order
andrew-fleming May 5, 2024
1266c55
add interface docs and start component docs
andrew-fleming May 5, 2024
2409cd3
document privateimpl in enum extension
andrew-fleming May 6, 2024
6f3524f
add privateimpl in erc721enum
andrew-fleming May 6, 2024
8d02fb4
add tests checking order of owner index
andrew-fleming May 6, 2024
72c65c1
fix supply tests, add camel tests
andrew-fleming May 6, 2024
7ef4de4
add ierc721enumerable selectors
andrew-fleming May 6, 2024
984000e
add dualcase erc721enumerable
andrew-fleming May 6, 2024
4e02b3c
add dualcase erc721enum tests
andrew-fleming May 6, 2024
a261677
fix formatting
andrew-fleming May 6, 2024
2c0474e
update changelog
andrew-fleming May 6, 2024
7f849dc
update changelog entry
andrew-fleming May 7, 2024
c3a029e
change _update to before_update
andrew-fleming May 7, 2024
72b75cd
fix formatting
andrew-fleming May 7, 2024
3170a7b
remove unused imports
andrew-fleming May 7, 2024
f904280
remove excess error, fix _remove_token_from_owner_enumeration
andrew-fleming May 11, 2024
33ee6b7
add internal tests
andrew-fleming May 11, 2024
66d7471
fix formatting
andrew-fleming May 11, 2024
33025cd
fix conflicts
andrew-fleming May 14, 2024
2a1f876
fix before_update description
andrew-fleming May 14, 2024
c5fdc29
revert comment change
andrew-fleming May 14, 2024
8e815ed
match comment with api description
andrew-fleming May 14, 2024
48b30c3
Apply suggestions from code review
andrew-fleming May 15, 2024
7b37352
remove enum selectors
andrew-fleming May 21, 2024
ffe01ad
remove dual_case and camel impls from erc721_enum
andrew-fleming May 21, 2024
359c711
remove unused mocks, fix mock name
andrew-fleming May 21, 2024
01b8687
remove dual and camel tests for erc721_enum
andrew-fleming May 21, 2024
e7e1459
remove camel impl from erc721_enum
andrew-fleming May 21, 2024
5a41e4e
Merge branch 'main' into erc721-enum
andrew-fleming May 21, 2024
68db79a
fix changelog
andrew-fleming May 21, 2024
a38c338
Merge branch 'erc721-enum' of https://github.com/andrew-fleming/cairo…
andrew-fleming May 21, 2024
0de7db4
fix conflicts, migrate to 2023_11
andrew-fleming Jun 18, 2024
65f6259
fix conflicts
andrew-fleming Jul 13, 2024
640faab
bump scarb to rc.2
andrew-fleming Jul 13, 2024
2a3af3f
use Map, allow tests to read storage
andrew-fleming Jul 13, 2024
a2e9bf7
fix fmt
andrew-fleming Jul 13, 2024
404c945
fix Contracts version
andrew-fleming Jul 13, 2024
867c2cf
fix test_names
andrew-fleming Jul 22, 2024
c4c78dc
fix spelling
andrew-fleming Jul 22, 2024
c8bbf06
move erc721 enum component section to core
andrew-fleming Jul 22, 2024
9fccfea
add component description
andrew-fleming Jul 22, 2024
45b66d0
fix intro section
andrew-fleming Jul 22, 2024
e462e2e
fix fmt
andrew-fleming Jul 22, 2024
fc68c8f
fix conflicts
andrew-fleming Jul 25, 2024
94f0854
fix conflicts
andrew-fleming Aug 2, 2024
3c9c325
change to while loops in assertions
andrew-fleming Aug 2, 2024
3dd3698
simplify fn calls with self
andrew-fleming Aug 13, 2024
dba11f5
remove zero var
andrew-fleming Aug 13, 2024
dd5f907
remove dual in helpers
andrew-fleming Aug 13, 2024
b983aa0
check supply/owner bal == expected token list
andrew-fleming Aug 13, 2024
80cff05
fix test names/add comments for ctx
andrew-fleming Aug 15, 2024
7ac8b36
improve assertion name
andrew-fleming Aug 15, 2024
8b79881
fix conflicts
andrew-fleming Aug 15, 2024
5b691a7
fix fmt
andrew-fleming Aug 15, 2024
b6c5611
update spdx license id
andrew-fleming Aug 15, 2024
9478f72
update version in docs
andrew-fleming Aug 16, 2024
1ede105
Apply suggestions from code review
andrew-fleming Aug 20, 2024
0d61150
remove privateimpl from code
andrew-fleming Aug 20, 2024
0b5e92c
remove privateimpl from docs
andrew-fleming Aug 20, 2024
a81fcac
remove after_update hook from mocks
andrew-fleming Aug 20, 2024
4bb50b6
Apply suggestions from code review
andrew-fleming Aug 23, 2024
0f863ba
use simpler hook impl
andrew-fleming Aug 23, 2024
9ae2345
add before_update code example
andrew-fleming Aug 23, 2024
0982314
fix conflicts
andrew-fleming Aug 23, 2024
abf6b66
Apply suggestions from code review
andrew-fleming Aug 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Added

- before_update and after_update hooks to ERC721Component (#978)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets not forget to add the entry to the changelog.


## 0.12.0 (2024-04-21)

### Added
Expand Down
185 changes: 137 additions & 48 deletions docs/modules/ROOT/pages/api/erc721.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,17 @@ ERC721 component implementing <<IERC721,IERC721>> and <<IERC721Metadata,IERC721M

NOTE: {src5-component-required-note}

NOTE: See xref:#ERC721Component-Hooks[Hooks] to understand how are hooks used.

[.contract-index]
.Hooks
--
[.sub-index#ERC721Component-ERC721HooksTrait]
.ERC721HooksTrait
* xref:#ERC721Component-before_update[`++before_update(self, to, token_id, auth)++`]
* xref:#ERC721Component-after_update[`++after_update(self, to, token_id, auth)++`]
--

[.contract-index#ERC721Component-Embeddable-Mixin-Impl]
.{mixin-impls}

Expand Down Expand Up @@ -248,9 +259,10 @@ NOTE: {src5-component-required-note}
.InternalImpl
* xref:#ERC721Component-initializer[`++initializer(self, name, symbol, base_uri)++`]
* xref:#ERC721Component-_owner_of[`++_owner_of(self, token_id)++`]
* xref:#ERC721Component-_require_owned[`++_owner_of(self, token_id)++`]
* xref:#ERC721Component-_exists[`++_exists(self, token_id)++`]
* xref:#ERC721Component-_is_approved_or_owner[`++_is_approved_or_owner(self, spender, token_id)++`]
* xref:#ERC721Component-_approve[`++_approve(self, to, token_id)++`]
* xref:#ERC721Component-_approve[`++_approve(self, to, token_id, auth)++`]
* xref:#ERC721Component-_approve_with_optional_event[`++_approve_with_optional_event(self, to, token_id, auth, emit_event)++`]
* xref:#ERC721Component-_set_approval_for_all[`++_set_approval_for_all(self, owner, operator, approved)++`]
* xref:#ERC721Component-_mint[`++_mint(self, to, token_id)++`]
* xref:#ERC721Component-_transfer[`++_transfer(self, from, to, token_id)++`]
Expand All @@ -259,6 +271,9 @@ NOTE: {src5-component-required-note}
* xref:#ERC721Component-_safe_transfer[`++_safe_transfer(self, from, to, token_id, data)++`]
* xref:#ERC721Component-_set_base_uri[`++_set_base_uri(self, base_uri)++`]
* xref:#ERC721Component-_base_uri[`++_base_uri(self)++`]
* xref:#ERC721Component-_is_authorized[`++_is_authorized(self, owner, spender, token_id)++`]
* xref:#ERC721Component-_check_authorized[`++_check_authorized(self, owner, spender, token_id)++`]
* xref:#ERC721Component-_update[`++_update(self, to, token_id, auth)++`]
--

[.contract-index]
Expand All @@ -270,6 +285,28 @@ NOTE: {src5-component-required-note}
* xref:#ERC721Component-Transfer[`++Transfer(from, to, token_id)++`]
--

[#ERC721Component-Hooks]
==== Hooks

Hooks are functions which implementations can extend the functionality of the component source code. Every contract
using ERC721Component is expected to provide an implementation of the ERC721HooksTrait. For basic token contracts, an
empty implementation with no logic must be provided.

TIP: You can use `openzeppelin::token::erc721::ERC721HooksEmptyImpl` which is already available as part of the library
for this purpose.

[.contract-item]
[[ERC721Component-before_update]]
==== `[.contract-item-name]#++before_update++#++(ref self: ContractState, to: ContractAddress, token_id: u256, auth: ContractAddress)++` [.item-kind]#hook#

Function executed at the beginning of the xref:#ERC721Component-_update[_update] function prior to any other logic.

[.contract-item]
[[ERC721Component-after_update]]
==== `[.contract-item-name]#++after_update++#++(ref self: ContractState, to: ContractAddress, token_id: u256, auth: ContractAddress)++` [.item-kind]#hook#

Function executed at the end of the xref:#ERC721Component-_update[_update] function.

==== Embeddable functions

[.contract-item]
Expand Down Expand Up @@ -379,49 +416,49 @@ If the URI is not set for `token_id`, the return value will be an empty `ByteArr
[[ERC721Component-balanceOf]]
==== `[.contract-item-name]#++balanceOf++#++(self: @ContractState, account: ContractAddress) -> u256++` [.item-kind]#external#

See <<IERC721-balance_of,IERC721::balance_of>>.
See <<ERC721Component-balance_of,ERC721Component::balance_of>>.

[.contract-item]
[[ERC721Component-ownerOf]]
==== `[.contract-item-name]#++ownerOf++#++(self: @ContractState, tokenId: u256) -> ContractAddress++` [.item-kind]#external#

See <<IERC721-owner_of,IERC721::owner_of>>.
See <<ERC721Component-owner_of,ERC721Component::owner_of>>.

[.contract-item]
[[ERC721Component-safeTransferFrom]]
==== `[.contract-item-name]#++safeTransferFrom++#++(ref self: ContractState, from: ContractAddress, to: ContractAddress, tokenId: u256, data: Span<felt252>)++` [.item-kind]#external#

See <<IERC721-safe_transfer_from,IERC721::safe_transfer_from>>.
See <<ERC721Component-safe_transfer_from,ERC721Component::safe_transfer_from>>.

[.contract-item]
[[ERC721Component-transferFrom]]
==== `[.contract-item-name]#++transferFrom++#++(ref self: ContractState, from: ContractAddress, to: ContractAddress, tokenId: u256)++` [.item-kind]#external#

See <<IERC721-transfer_from,IERC721::transfer_from>>.
See <<ERC721Component-transfer_from,ERC721Component::transfer_from>>.

[.contract-item]
[[ERC721Component-setApprovalForAll]]
==== `[.contract-item-name]#++setApprovalForAll++#++(ref self: ContractState, operator: ContractAddress, approved: bool)++` [.item-kind]#external#

See <<IERC721-safe_transfer_from,IERC721::safe_transfer_from>>.
See <<ERC721Component-set_approval_for_all,ERC721Component::set_approval_for_all>>.

[.contract-item]
[[ERC721Component-getApproved]]
==== `[.contract-item-name]#++getApproved++#++(self: @ContractState, tokenId: u256) -> ContractAddress++` [.item-kind]#external#

See <<IERC721-get_approved,IERC721::get_approved>>.
See <<ERC721Component-get_approved,ERC721Component::get_approved>>.

[.contract-item]
[[ERC721Component-isApprovedForAll]]
==== `[.contract-item-name]#++isApprovedForAll++#++(self: @ContractState, owner: ContractAddress, operator: ContractAddress) -> bool++` [.item-kind]#external#

See <<IERC721-is_approved_for_all,IERC721::is_approved_for_all>>.
See <<ERC721Component-is_approved_for_all,ERC721Component::is_approved_for_all>>.

[.contract-item]
[[ERC721Component-tokenURI]]
==== `[.contract-item-name]#++tokenURI++#++(self: @ContractState, tokenId: u256) -> ByteArray++` [.item-kind]#external#

See <<IERC721Metadata-token_uri,IERC721Metadata::token_uri>>.
See <<ERC721Component-token_uri,ERC721Component::token_uri>>.

==== Internal functions

Expand All @@ -437,7 +474,12 @@ This should be used inside the contract's constructor.
==== `[.contract-item-name]#++_owner_of++#++(self: @ContractState, token_id: felt252) -> ContractAddress++` [.item-kind]#internal#

Internal function that returns the owner address of `token_id`.
This function will panic if the token does not exist.

[.contract-item]
[[ERC721Component-_require_owned]]
==== `[.contract-item-name]#++_require_owned++#++(self: @ContractState, token_id: felt252) -> ContractAddress++` [.item-kind]#internal#

Version of xref:#ERC721Component-_owner_of[_owner_of] that panics if owner is the zero address.

[.contract-item]
[[ERC721Component-_exists]]
Expand All @@ -448,114 +490,121 @@ Internal function that returns whether `token_id` exists.
Tokens start existing when they are minted (<<ERC721-_mint,_mint>>), and stop existing when they are burned (<<ERC721-_burn,_burn>>).

[.contract-item]
[[ERC721Component-_is_approved_or_owner]]
==== `[.contract-item-name]#++_is_approved_or_owner++#++(ref self: ContractState, spender: ContractAddress, token_id: u256) -> bool++` [.item-kind]#internal#
[[ERC721Component-_approve]]
==== `[.contract-item-name]#++_approve++#++(ref self: ContractState, to: ContractAddress, token_id: u256, auth: ContractAddress)++` [.item-kind]#internal#

Internal function that returns whether `spender` is allowed to manage `token_id`.
Approve `to` to operate on `token_id`

Requirements:
The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
either the owner of the token, or approved to operate on all tokens held by this owner.

- `token_id` exists.
Emits an <<IERC721-Approval,Approval>> event.

[.contract-item]
[[ERC721Component-_approve]]
==== `[.contract-item-name]#++_approve++#++(ref self: ContractState, to: ContractAddress, token_id: u256)++` [.item-kind]#internal#
[[ERC721Component-_approve_with_optional_event]]
==== `[.contract-item-name]#++_approve_with_optional_event++#++(ref self: ContractState, to: ContractAddress, token_id: u256, auth: ContractAddress, emit_event: bool)++` [.item-kind]#internal#

Internal function that changes or reaffirms the approved address for an NFT.

Emits an <<IERC721-Approval,Approval>> event.
Variant of xref:#ERC721Component-_approve[_approve] with an optional flag to enable or disable the `Approval` event.
The event is not emitted in the context of transfers.

Requirements:

- `token_id` exists.
- `to` is not the current token owner.
- if `auth` is non-zero, it must be either the owner of the token or approved to
operate on all of its tokens.

May emit an <<IERC721-Approval,Approval>> event.

[.contract-item]
[[ERC721Component-_set_approval_for_all]]
==== `[.contract-item-name]#++_set_approval_for_all++#++(ref self: ContractState, owner: ContractAddress, operator: ContractAddress, approved: bool)++` [.item-kind]#internal#

Internal function that enables or disables approval for `operator` to manage all of the
`owner` assets.

Emits an <<IERC721-Approval,Approval>> event.
Enables or disables approval for `operator` to manage
all of the `owner` assets.

Requirements:

- `operator` cannot be the caller.

Emits an <<IERC721-Approval,Approval>> event.

[.contract-item]
[[ERC721Component-_mint]]
==== `[.contract-item-name]#++_mint++#++(ref self: ContractState, to: ContractAddress, token_id: u256)++` [.item-kind]#internal#

Internal function that mints `token_id` and transfers it to `to`.
Mints `token_id` and transfers it to `to`.
Internal function without access restriction.

Emits an <<IERC721-Transfer,Transfer>> event.
WARNING: Usage of this method is discouraged, use `_safe_mint` whenever possible

Requirements:

- `to` is not the zero address.
- `token_id` does not already exist.
- `token_id` must not exist.

Emits a <<IERC721-Transfer,Transfer>> event.

[.contract-item]
[[ERC721Component-_transfer]]
==== `[.contract-item-name]#++_transfer++#++(ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256)++` [.item-kind]#internal#

Internal function that transfers `token_id` from `from` to `to`.
Transfers `token_id` from `from` to `to`.

Emits an <<IERC721-Transfer,Transfer>> event.
Internal function without access restriction.

Requirements:

- `to` is not the zero address.
- `from` is the token owner.
- `token_id` exists.

Emits a <<IERC721-Transfer,Transfer>> event.

[.contract-item]
[[ERC721Component-_burn]]
==== `[.contract-item-name]#++_burn++#++(ref self: ContractState, token_id: u256)++` [.item-kind]#internal#

Internal function that destroys `token_id`.
The approval is cleared when the token is burned.
This internal function does not check if the sender is authorized to operate on the token.
Destroys `token_id`. The approval is cleared when the token is burned.

Emits an <<IERC721-Transfer,Transfer>> event.
This internal function does not check if the caller is authorized
to operate on the token.

Requirements:

`token_id` exists.
- `token_id` exists.

Emits a <<IERC721-Transfer,Transfer>> event.

[.contract-item]
[[ERC721Component-_safe_mint]]
==== `[.contract-item-name]#++_safe_mint++#++(ref self: ContractState, to: ContractAddress, token_id: u256, data: Span<felt252>)++` [.item-kind]#internal#

Internal function that mints `token_id` and transfers it to `to`.
If `to` is not an account contract, `to` must support <<IERC721Receiver,IERC721Receiver>>; otherwise, the transaction will fail.
Mints `token_id` if `to` is either an account or `IERC721Receiver`.

Emits an <<IERC721-Transfer,Transfer>> event.
`data` is additional data, it has no specified format and it is sent in call to `to`.

Requirements:

- `token_id` does not already exist.
- `to` is either an account contract or supports the <<IERC721Receiver,IERC721Receiver>> interface.
- `token_id` does not exist.
- `to` is either an account contract or supports the `IERC721Receiver` interface.

Emits a <<IERC721-Transfer,Transfer>> event.

[.contract-item]
[[ERC721Component-_safe_transfer]]
==== `[.contract-item-name]#++_safe_transfer++#++(ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256, data: Span<felt252>)++` [.item-kind]#internal#

Internal function that transfers `token_id` token from `from` to `to`, checking first that contract recipients are aware of the ERC721 protocol to prevent tokens from being forever locked.
Transfers ownership of `token_id` from `from` if `to` is either an account or `IERC721Receiver`.

`data` is additional data, it has no specified format and it is sent in call to `to`.

This internal function does not include permissions but can be useful for instances like implementing alternative mechanisms to perform signature-based token transfers.

Emits an <<IERC721-Transfer,Transfer>> event.

Requirements:

- `to` cannot be the zero address.
- `from` must be the token owner.
- `token_id` exists.
- `to` either is an account contract or supports the <<IERC721Receiver,IERC721Receiver>> interface.
- `to` is either an account contract or supports the `IERC721Receiver` interface.

Emits a <<IERC721-Transfer,Transfer>> event.

[.contract-item]
[[ERC721Component-_set_base_uri]]
Expand All @@ -569,6 +618,46 @@ Internal function that sets the `base_uri`.

Base URI for computing <<IERC721Metadata-token_uri, token_uri>>.

If set, the resulting URI for each token will be the concatenation of the base URI and the token ID.
Returns an empty `ByteArray` if not set.

[.contract-item]
[[ERC721Component-_is_authorized]]
==== `[.contract-item-name]#++_is_authorized++#++(self: @ContractState, owner: ContractAddress, spender: ContractAddress, token_id: u256) -> bool++` [.item-kind]#internal#

Returns whether `spender` is allowed to manage ``owner``'s tokens, or `token_id` in
particular (ignoring whether it is owned by `owner`).

WARNING: This function assumes that `owner` is the actual owner of `token_id` and does not verify this
assumption.

[.contract-item]
[[ERC721Component-_check_authorized]]
==== `[.contract-item-name]#++_check_authorized++#++(self: @ContractState, owner: ContractAddress, spender: ContractAddress, token_id: u256) -> bool++` [.item-kind]#internal#

Checks if `spender` can operate on `token_id`, assuming the provided `owner` is the actual owner.

Requirements:

- `owner` cannot be the zero address.
- `spender` cannot be the zero address.
- `spender` must be the owner of `token_id` or be approved to operate on it.

WARNING: This function assumes that `owner` is the actual owner of `token_id` and does not verify this
assumption.

[.contract-item]
[[ERC721Component-_update]]
==== `[.contract-item-name]#++_update++#++(ref self: ContractState, to: ContractAddress, token_id: u256, auth: ContractAddress)++` [.item-kind]#internal#

Transfers `token_id` from its current owner to `to`, or alternatively mints (or burns) if the current owner
(or `to`) is the zero address. Returns the owner of the `token_id` before the update.

The `auth` argument is optional. If the value passed is non 0, then this function will check that
`auth` is either the owner of the token, or approved to operate on the token (by the owner).

Emits a <<IERC721-Transfer,Transfer>> event.

==== Events

[.contract-item]
Expand Down
3 changes: 1 addition & 2 deletions src/presets/erc721.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
mod ERC721Upgradeable {
use openzeppelin::access::ownable::OwnableComponent;
use openzeppelin::introspection::src5::SRC5Component;
use openzeppelin::token::erc721::ERC721Component;
use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl};
use openzeppelin::upgrades::UpgradeableComponent;
use openzeppelin::upgrades::interface::IUpgradeable;
use starknet::{ContractAddress, ClassHash};
Expand Down Expand Up @@ -100,7 +100,6 @@ mod ERC721Upgradeable {
break;
}
let id = *token_ids.pop_front().unwrap();

self.erc721._mint(recipient, id);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/tests/mocks.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod erc1155_mocks;
mod erc1155_receiver_mocks;
mod erc20_mocks;
mod erc20_votes_mocks;
mod erc721_enumerable_mocks;
mod erc721_mocks;
mod erc721_receiver_mocks;
mod eth_account_mocks;
Expand Down
Loading
Loading