From 88f68d47e539c68975ce726eb7804f4b4bfd8a4d Mon Sep 17 00:00:00 2001 From: bal7hazar Date: Tue, 28 Nov 2023 10:36:02 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20presets=20-?= =?UTF-8?q?=20Rename=20into=20token=20-=20Add=20token=20into=20workspace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Scarb.lock | 9 +- Scarb.toml | 4 +- presets/Scarb.toml | 9 -- presets/src/erc1155/erc1155.cairo | 5 -- presets/src/lib.cairo | 13 --- {presets => token}/.gitignore | 0 {presets => token}/Scarb.lock | 0 token/Scarb.toml | 8 ++ .../src}/erc1155/erc1155.cairo | 56 +------------ .../src}/erc1155/interface.cairo | 0 .../src}/erc1155/models.cairo | 2 + {presets => token}/src/erc1155/tests.cairo | 22 ++--- {presets => token}/src/erc20/erc20.cairo | 16 +--- token/src/erc20/interface.cairo | 24 ++++++ {presets => token}/src/erc20/models.cairo | 16 ++-- {presets => token}/src/erc20/tests.cairo | 18 ++-- {presets => token}/src/erc721/erc721.cairo | 84 +++++++------------ token/src/erc721/interface.cairo | 60 +++++++++++++ {presets => token}/src/erc721/models.cairo | 0 {presets => token}/src/erc721/tests.cairo | 22 ++--- token/src/lib.cairo | 32 +++++++ {presets => token}/src/tests/constants.cairo | 0 .../src/tests/test_erc1155.cairo | 0 .../src/tests/test_erc721.cairo | 0 {presets => token}/src/tests/utils.cairo | 0 25 files changed, 212 insertions(+), 188 deletions(-) delete mode 100644 presets/Scarb.toml delete mode 100644 presets/src/erc1155/erc1155.cairo delete mode 100644 presets/src/lib.cairo rename {presets => token}/.gitignore (100%) rename {presets => token}/Scarb.lock (100%) create mode 100644 token/Scarb.toml rename {presets/src/erc1155 => token/src}/erc1155/erc1155.cairo (84%) rename {presets/src/erc1155 => token/src}/erc1155/interface.cairo (100%) rename {presets/src/erc1155 => token/src}/erc1155/models.cairo (96%) rename {presets => token}/src/erc1155/tests.cairo (97%) rename {presets => token}/src/erc20/erc20.cairo (96%) create mode 100644 token/src/erc20/interface.cairo rename {presets => token}/src/erc20/models.cairo (59%) rename {presets => token}/src/erc20/tests.cairo (97%) rename {presets => token}/src/erc721/erc721.cairo (90%) create mode 100644 token/src/erc721/interface.cairo rename {presets => token}/src/erc721/models.cairo (100%) rename {presets => token}/src/erc721/tests.cairo (98%) create mode 100644 token/src/lib.cairo rename {presets => token}/src/tests/constants.cairo (100%) rename {presets => token}/src/tests/test_erc1155.cairo (100%) rename {presets => token}/src/tests/test_erc721.cairo (100%) rename {presets => token}/src/tests/utils.cairo (100%) diff --git a/Scarb.lock b/Scarb.lock index 7b6f657c..32bdc800 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -38,7 +38,7 @@ dependencies = [ [[package]] name = "origami" -version = "0.1.0" +version = "0.0.0" dependencies = [ "cubit", "dojo", @@ -52,3 +52,10 @@ dependencies = [ "dojo", "origami", ] + +[[package]] +name = "token" +version = "0.0.0" +dependencies = [ + "dojo", +] diff --git a/Scarb.toml b/Scarb.toml index 7c419124..a6c76780 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,8 +1,8 @@ [workspace] -members = ["crates", "examples/*"] +members = ["crates", "examples/*", "token"] [workspace.package] -version = "0.1.0" +version = "0.0.0" description = "Community-maintained libraries for Cairo" homepage = "https://github.com/dojoengine/origami" authors = ["bal7hazar@proton.me"] diff --git a/presets/Scarb.toml b/presets/Scarb.toml deleted file mode 100644 index 67dbbe95..00000000 --- a/presets/Scarb.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "presets" -version = "0.0.0" -description = "Implementations of ERC standards for the Dojo framework." -homepage = "https://github.com/dojoengine/origami/tree/presets" - -[dependencies] -dojo = { git = "https://github.com/dojoengine/dojo.git", rev = "d62ec8a" } -openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", rev = "4eafccf" } \ No newline at end of file diff --git a/presets/src/erc1155/erc1155.cairo b/presets/src/erc1155/erc1155.cairo deleted file mode 100644 index aeb7f33a..00000000 --- a/presets/src/erc1155/erc1155.cairo +++ /dev/null @@ -1,5 +0,0 @@ -mod erc1155; -mod models; -mod interface; - -use erc1155::ERC1155; diff --git a/presets/src/lib.cairo b/presets/src/lib.cairo deleted file mode 100644 index c6129437..00000000 --- a/presets/src/lib.cairo +++ /dev/null @@ -1,13 +0,0 @@ -mod erc721 { - mod models; - mod erc721; - use erc721::ERC721; - #[cfg(test)] - mod tests; -} - -#[cfg(test)] -mod tests { - mod constants; - mod utils; -} diff --git a/presets/.gitignore b/token/.gitignore similarity index 100% rename from presets/.gitignore rename to token/.gitignore diff --git a/presets/Scarb.lock b/token/Scarb.lock similarity index 100% rename from presets/Scarb.lock rename to token/Scarb.lock diff --git a/token/Scarb.toml b/token/Scarb.toml new file mode 100644 index 00000000..7e3eaf76 --- /dev/null +++ b/token/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "token" +version = "0.0.0" +description = "Implementations of ERC standards for the Dojo framework." +homepage = "https://github.com/dojoengine/origami/tree/presets" + +[dependencies] +dojo.workspace = true \ No newline at end of file diff --git a/presets/src/erc1155/erc1155/erc1155.cairo b/token/src/erc1155/erc1155.cairo similarity index 84% rename from presets/src/erc1155/erc1155/erc1155.cairo rename to token/src/erc1155/erc1155.cairo index ff633a30..331fcefc 100644 --- a/presets/src/erc1155/erc1155/erc1155.cairo +++ b/token/src/erc1155/erc1155.cairo @@ -1,8 +1,8 @@ #[starknet::contract] mod ERC1155 { - use dojo_erc::token::erc1155::models::{ERC1155Meta, ERC1155OperatorApproval, ERC1155Balance}; - use dojo_erc::token::erc1155::interface; - use dojo_erc::token::erc1155::interface::{IERC1155, IERC1155CamelOnly}; + use token::erc1155::models::{ERC1155Meta, ERC1155OperatorApproval, ERC1155Balance}; + use token::erc1155::interface; + use token::erc1155::interface::{IERC1155, IERC1155CamelOnly}; use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; use starknet::ContractAddress; use starknet::{get_caller_address, get_contract_address}; @@ -73,26 +73,6 @@ mod ERC1155 { self.initializer(name, symbol, base_uri); } - // - // External - // - - // #[external(v0)] - // impl SRC5Impl of ISRC5 { - // fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - // let unsafe_state = src5::SRC5::unsafe_new_contract_state(); - // src5::SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id) - // } - // } - - // #[external(v0)] - // impl SRC5CamelImpl of ISRC5Camel { - // fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - // let unsafe_state = src5::SRC5::unsafe_new_contract_state(); - // src5::SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) - // } - // } - #[external(v0)] impl ERC1155MetadataImpl of interface::IERC1155Metadata { fn name(self: @ContractState) -> felt252 { @@ -297,11 +277,6 @@ mod ERC1155 { fn initializer(ref self: ContractState, name: felt252, symbol: felt252, base_uri: felt252) { let meta = ERC1155Meta { token: get_contract_address(), name, symbol, base_uri }; set!(self.world(), (meta)); - // let mut unsafe_state = src5::SRC5::unsafe_new_contract_state(); - // src5::SRC5::InternalImpl::register_interface(ref unsafe_state, interface::IERC721_ID); - // src5::SRC5::InternalImpl::register_interface( - // ref unsafe_state, interface::IERC721_METADATA_ID - // ); } fn _is_approved_for_all_or_owner( @@ -329,9 +304,6 @@ mod ERC1155 { data: Array ) { self.update_balances(from, to, id, amount); - // assert( - // _check_on_erc1155_received(from, to, id, data), Errors::SAFE_TRANSFER_FAILED - // ); self .emit_event( @@ -359,9 +331,6 @@ mod ERC1155 { let id = *ids_span.pop_front().unwrap(); let amount = *amounts_span.pop_front().unwrap(); self.update_balances(from, to, id, amount); - // assert( - // _check_on_erc1155_received(from, to, id, data), Errors::SAFE_TRANSFER_FAILED - // ); }; self @@ -413,25 +382,6 @@ mod ERC1155 { data: Span ) { self._mint(to, id, amount); - // assert( - // _check_on_erc1155_received(Zeroable::zero(), to, id, data), - // Errors::SAFE_MINT_FAILED - // ); } } -//#[internal] -// fn _check_on_erc1155_received( -// from: ContractAddress, to: ContractAddress, token_id: u256, data: Span -// ) -> bool { -// if (DualCaseSRC5 { contract_address: to } -// .supports_interface(interface::IERC1155_RECEIVER_ID)) { -// DualCaseERC1155Receiver { contract_address: to } -// .on_erc1155_received( -// get_caller_address(), from, token_id, data -// ) == interface::IERC1155_RECEIVER_ID -// } else { -// DualCaseSRC5 { contract_address: to }.supports_interface(account::interface::ISRC6_ID) -// } -// } - } diff --git a/presets/src/erc1155/erc1155/interface.cairo b/token/src/erc1155/interface.cairo similarity index 100% rename from presets/src/erc1155/erc1155/interface.cairo rename to token/src/erc1155/interface.cairo diff --git a/presets/src/erc1155/erc1155/models.cairo b/token/src/erc1155/models.cairo similarity index 96% rename from presets/src/erc1155/erc1155/models.cairo rename to token/src/erc1155/models.cairo index 3e1861e3..a448b469 100644 --- a/presets/src/erc1155/erc1155/models.cairo +++ b/token/src/erc1155/models.cairo @@ -1,3 +1,5 @@ +// Starknet imports + use starknet::ContractAddress; #[derive(Model, Copy, Drop, Serde)] diff --git a/presets/src/erc1155/tests.cairo b/token/src/erc1155/tests.cairo similarity index 97% rename from presets/src/erc1155/tests.cairo rename to token/src/erc1155/tests.cairo index 6951695b..3447581b 100644 --- a/presets/src/erc1155/tests.cairo +++ b/token/src/erc1155/tests.cairo @@ -1,16 +1,16 @@ -use dojo_erc::tests::utils; -use dojo_erc::tests::constants::{ +use token::tests::utils; +use token::tests::constants::{ ZERO, OWNER, SPENDER, RECIPIENT, OPERATOR, OTHER, NAME, SYMBOL, URI, TOKEN_ID, TOKEN_AMOUNT, TOKEN_ID_2, TOKEN_AMOUNT_2 }; -use dojo_erc::token::erc1155::ERC1155::ERC1155Impl; -use dojo_erc::token::erc1155::ERC1155::ERC1155CamelOnlyImpl; -use dojo_erc::token::erc1155::ERC1155::ERC1155MetadataImpl; -use dojo_erc::token::erc1155::ERC1155::InternalImpl; -use dojo_erc::token::erc1155::ERC1155::WorldInteractionsImpl; -use dojo_erc::token::erc1155::ERC1155::{TransferSingle, TransferBatch, ApprovalForAll}; -use dojo_erc::token::erc1155::ERC1155; +use token::erc1155::ERC1155::ERC1155Impl; +use token::erc1155::ERC1155::ERC1155CamelOnlyImpl; +use token::erc1155::ERC1155::ERC1155MetadataImpl; +use token::erc1155::ERC1155::InternalImpl; +use token::erc1155::ERC1155::WorldInteractionsImpl; +use token::erc1155::ERC1155::{TransferSingle, TransferBatch, ApprovalForAll}; +use token::erc1155::ERC1155; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing; @@ -18,11 +18,11 @@ use zeroable::Zeroable; use dojo::test_utils::spawn_test_world; use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; -use dojo_erc::token::erc1155::models::{ +use token::erc1155::models::{ ERC1155Meta, erc_1155_meta, ERC1155OperatorApproval, erc_1155_operator_approval, ERC1155Balance, erc_1155_balance }; -use dojo_erc::token::erc1155::ERC1155::_worldContractMemberStateTrait; +use token::erc1155::ERC1155::_worldContractMemberStateTrait; use debug::PrintTrait; // diff --git a/presets/src/erc20/erc20.cairo b/token/src/erc20/erc20.cairo similarity index 96% rename from presets/src/erc20/erc20.cairo rename to token/src/erc20/erc20.cairo index d21be836..7550d963 100644 --- a/presets/src/erc20/erc20.cairo +++ b/token/src/erc20/erc20.cairo @@ -1,20 +1,12 @@ -// External imports - -use openzeppelin::token::erc20::interface; - #[starknet::contract] mod ERC20 { - use dojo_erc::token::erc20_models::{ERC20Allowance, ERC20Balance, ERC20Meta}; + use token::erc20::models::{ERC20Allowance, ERC20Balance, ERC20Meta}; use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; + use token::erc20::interface; use integer::BoundedInt; use starknet::ContractAddress; use starknet::{get_caller_address, get_contract_address}; use zeroable::Zeroable; - use debug::PrintTrait; - - // Local imports - - use super::interface::{IERC20, IERC20CamelOnly}; #[storage] @@ -71,7 +63,7 @@ mod ERC20 { // #[external(v0)] - impl ERC20Impl of IERC20 { + impl ERC20Impl of interface::IERC20 { fn name(self: @ContractState) -> felt252 { self.get_meta().name } @@ -127,7 +119,7 @@ mod ERC20 { } #[external(v0)] - impl ERC20CamelOnlyImpl of IERC20CamelOnly { + impl ERC20CamelOnlyImpl of interface::IERC20CamelOnly { fn totalSupply(self: @ContractState) -> u256 { ERC20Impl::total_supply(self) } diff --git a/token/src/erc20/interface.cairo b/token/src/erc20/interface.cairo new file mode 100644 index 00000000..e0778409 --- /dev/null +++ b/token/src/erc20/interface.cairo @@ -0,0 +1,24 @@ +use starknet::ContractAddress; + +#[starknet::interface] +trait IERC20 { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn decimals(self: @TState) -> u8; + fn total_supply(self: @TState) -> u256; + fn balance_of(self: @TState, account: ContractAddress) -> u256; + fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; +} + +trait IERC20CamelOnly { + fn totalSupply(self: @TState) -> u256; + fn balanceOf(self: @TState, account: ContractAddress) -> u256; + fn transferFrom( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; +} diff --git a/presets/src/erc20/models.cairo b/token/src/erc20/models.cairo similarity index 59% rename from presets/src/erc20/models.cairo rename to token/src/erc20/models.cairo index f19cda5c..13612f0f 100644 --- a/presets/src/erc20/models.cairo +++ b/token/src/erc20/models.cairo @@ -1,27 +1,31 @@ +// Starknet imports + +use starknet::ContractAddress; + #[derive(Model, Copy, Drop, Serde)] struct ERC20Balance { #[key] - token: starknet::ContractAddress, + token: ContractAddress, #[key] - account: starknet::ContractAddress, + account: ContractAddress, amount: u256, } #[derive(Model, Copy, Drop, Serde)] struct ERC20Allowance { #[key] - token: starknet::ContractAddress, + token: ContractAddress, #[key] - owner: starknet::ContractAddress, + owner: ContractAddress, #[key] - spender: starknet::ContractAddress, + spender: ContractAddress, amount: u256, } #[derive(Model, Copy, Drop, Serde)] struct ERC20Meta { #[key] - token: starknet::ContractAddress, + token: ContractAddress, name: felt252, symbol: felt252, total_supply: u256, diff --git a/presets/src/erc20/tests.cairo b/token/src/erc20/tests.cairo similarity index 97% rename from presets/src/erc20/tests.cairo rename to token/src/erc20/tests.cairo index 669cfc7c..7db32972 100644 --- a/presets/src/erc20/tests.cairo +++ b/token/src/erc20/tests.cairo @@ -1,15 +1,15 @@ use integer::BoundedInt; use integer::u256; use integer::u256_from_felt252; -use dojo_erc::tests::utils; -use dojo_erc::tests::constants::{ +use token::tests::utils; +use token::tests::constants::{ ZERO, OWNER, SPENDER, RECIPIENT, NAME, SYMBOL, DECIMALS, SUPPLY, VALUE }; -use dojo_erc::token::erc20::ERC20::Approval; -use dojo_erc::token::erc20::ERC20::ERC20Impl; -use dojo_erc::token::erc20::ERC20::InternalImpl; -use dojo_erc::token::erc20::ERC20::Transfer; -use dojo_erc::token::erc20::ERC20; +use token::erc20::ERC20::Approval; +use token::erc20::ERC20::ERC20Impl; +use token::erc20::ERC20::InternalImpl; +use token::erc20::ERC20::Transfer; +use token::erc20::ERC20; use starknet::ContractAddress; use starknet::contract_address_const; use starknet::testing; @@ -17,10 +17,10 @@ use zeroable::Zeroable; use dojo::test_utils::spawn_test_world; use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; -use dojo_erc::token::erc20_models::{ +use token::erc20::models::{ ERC20Allowance, erc_20_allowance, ERC20Balance, erc_20_balance, ERC20Meta, erc_20_meta }; -use dojo_erc::token::erc20::ERC20::_worldContractMemberStateTrait; +use token::erc20::ERC20::_worldContractMemberStateTrait; use debug::PrintTrait; // diff --git a/presets/src/erc721/erc721.cairo b/token/src/erc721/erc721.cairo similarity index 90% rename from presets/src/erc721/erc721.cairo rename to token/src/erc721/erc721.cairo index 4a181988..36d75b89 100644 --- a/presets/src/erc721/erc721.cairo +++ b/token/src/erc721/erc721.cairo @@ -1,67 +1,27 @@ -// External imports - -use openzeppelin::token::erc721::interface; - #[starknet::contract] mod ERC721 { - // Core imports - + use token::erc721::models::{ + ERC721Meta, ERC721OperatorApproval, ERC721Owner, ERC721Balance, ERC721TokenApproval + }; + use token::erc721::interface; + use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; use integer::BoundedInt; - use zeroable::Zeroable; - - // Starknet imports - use starknet::ContractAddress; use starknet::{get_caller_address, get_contract_address}; + use zeroable::Zeroable; - // Dojo imports - - use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; - - // External imports - - use openzeppelin::token::erc721::erc721::ERC721; - use openzeppelin::introspection::interface::{ISRC5, ISRC5Camel}; - use openzeppelin::introspection::src5::SRC5Component; - - // Internal imports - - use presets::erc721::models::{ - ERC721Meta, ERC721OperatorApproval, ERC721Owner, ERC721Balance, ERC721TokenApproval, - }; - - // Local imports - - use super::interface; - - // Components - - component!(path: SRC5Component, storage: src5, event: SRC5Event); - #[abi(embed_v0)] - impl SRC5Impl = SRC5Component::SRC5Impl; - #[abi(embed_v0)] - impl SRC5CamelImpl = SRC5Component::SRC5CamelImpl; - impl SRC5InternalImpl = SRC5Component::InternalImpl; - impl SRC5EventCopy of Copy {} - - // Storage #[storage] struct Storage { _world: ContractAddress, - #[substorage(v0)] - src5: SRC5Component::Storage } - // Events - #[event] #[derive(Copy, Drop, starknet::Event)] enum Event { Transfer: Transfer, Approval: Approval, - ApprovalForAll: ApprovalForAll, - SRC5Event: SRC5Component::Event, + ApprovalForAll: ApprovalForAll } #[derive(Copy, Drop, starknet::Event)] @@ -94,6 +54,8 @@ mod ERC721 { const INVALID_RECEIVER: felt252 = 'ERC721: invalid receiver'; const ALREADY_MINTED: felt252 = 'ERC721: token already minted'; const WRONG_SENDER: felt252 = 'ERC721: wrong sender'; + const SAFE_MINT_FAILED: felt252 = 'ERC721: safe mint failed'; + const SAFE_TRANSFER_FAILED: felt252 = 'ERC721: safe transfer failed'; } #[constructor] @@ -111,10 +73,6 @@ mod ERC721 { self._mint(recipient, token_id); } - // - // External - // - #[external(v0)] impl ERC721MetadataImpl of interface::IERC721Metadata { fn name(self: @ContractState) -> felt252 { @@ -135,7 +93,8 @@ mod ERC721 { #[external(v0)] impl ERC721MetadataCamelOnlyImpl of interface::IERC721MetadataCamelOnly { fn tokenURI(self: @ContractState, tokenId: u256) -> felt252 { - self.token_uri(tokenId) + assert(self._exists(tokenId), Errors::INVALID_TOKEN_ID); + self.get_uri(tokenId) } } @@ -197,8 +156,7 @@ mod ERC721 { assert( self._is_approved_or_owner(get_caller_address(), token_id), Errors::UNAUTHORIZED ); - // TODO: move to real safe transfer when support of SRC6 is enabled - self.transfer_from(from, to, token_id); + self._safe_transfer(from, to, token_id, data); } } @@ -332,8 +290,6 @@ mod ERC721 { fn initializer(ref self: ContractState, name: felt252, symbol: felt252, base_uri: felt252) { let meta = ERC721Meta { token: get_contract_address(), name, symbol, base_uri }; set!(self.world(), (meta)); - self.src5.register_interface(interface::IERC721_ID); - self.src5.register_interface(interface::IERC721_METADATA_ID); } fn _owner_of(self: @ContractState, token_id: u256) -> ContractAddress { @@ -414,5 +370,21 @@ mod ERC721 { self.emit_event(Transfer { from: owner, to: Zeroable::zero(), token_id }); } + + fn _safe_mint( + ref self: ContractState, to: ContractAddress, token_id: u256, data: Span + ) { + self._mint(to, token_id); + } + + fn _safe_transfer( + ref self: ContractState, + from: ContractAddress, + to: ContractAddress, + token_id: u256, + data: Span + ) { + self._transfer(from, to, token_id); + } } } diff --git a/token/src/erc721/interface.cairo b/token/src/erc721/interface.cairo new file mode 100644 index 00000000..730ad2e0 --- /dev/null +++ b/token/src/erc721/interface.cairo @@ -0,0 +1,60 @@ +use starknet::ContractAddress; + +const IERC721_ID: felt252 = 0x33eb2f84c309543403fd69f0d0f363781ef06ef6faeb0131ff16ea3175bd943; +const IERC721_METADATA_ID: felt252 = + 0x6069a70848f907fa57668ba1875164eb4dcee693952468581406d131081bbd; +const IERC721_RECEIVER_ID: felt252 = + 0x3a0dff5f70d80458ad14ae37bb182a728e3c8cdda0402a5daa86620bdf910bc; + +#[starknet::interface] +trait IERC721 { + fn balance_of(self: @TState, account: ContractAddress) -> u256; + fn owner_of(self: @TState, token_id: u256) -> ContractAddress; + fn transfer_from(ref self: TState, from: ContractAddress, to: ContractAddress, token_id: u256); + fn safe_transfer_from( + ref self: TState, + from: ContractAddress, + to: ContractAddress, + token_id: u256, + data: Span + ); + fn approve(ref self: TState, to: ContractAddress, token_id: u256); + fn set_approval_for_all(ref self: TState, operator: ContractAddress, approved: bool); + fn get_approved(self: @TState, token_id: u256) -> ContractAddress; + fn is_approved_for_all( + self: @TState, owner: ContractAddress, operator: ContractAddress + ) -> bool; +} + +#[starknet::interface] +trait IERC721CamelOnly { + fn balanceOf(self: @TState, account: ContractAddress) -> u256; + fn ownerOf(self: @TState, tokenId: u256) -> ContractAddress; + fn transferFrom(ref self: TState, from: ContractAddress, to: ContractAddress, tokenId: u256); + fn safeTransferFrom( + ref self: TState, + from: ContractAddress, + to: ContractAddress, + tokenId: u256, + data: Span + ); + fn setApprovalForAll(ref self: TState, operator: ContractAddress, approved: bool); + fn getApproved(self: @TState, tokenId: u256) -> ContractAddress; + fn isApprovedForAll(self: @TState, owner: ContractAddress, operator: ContractAddress) -> bool; +} + +// +// IERC721Metadata +// + +#[starknet::interface] +trait IERC721Metadata { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn token_uri(self: @TState, token_id: u256) -> felt252; +} + +#[starknet::interface] +trait IERC721MetadataCamelOnly { + fn tokenURI(self: @TState, tokenId: u256) -> felt252; +} diff --git a/presets/src/erc721/models.cairo b/token/src/erc721/models.cairo similarity index 100% rename from presets/src/erc721/models.cairo rename to token/src/erc721/models.cairo diff --git a/presets/src/erc721/tests.cairo b/token/src/erc721/tests.cairo similarity index 98% rename from presets/src/erc721/tests.cairo rename to token/src/erc721/tests.cairo index 778a4814..646daaa2 100644 --- a/presets/src/erc721/tests.cairo +++ b/token/src/erc721/tests.cairo @@ -20,22 +20,22 @@ use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; // Internal imports -use presets::tests::utils; -use presets::tests::constants::{ +use token::tests::utils; +use token::tests::constants::{ ZERO, OWNER, SPENDER, RECIPIENT, OPERATOR, OTHER, NAME, SYMBOL, URI, TOKEN_ID }; -use presets::erc721::ERC721::ERC721Impl; -use presets::erc721::ERC721::ERC721CamelOnlyImpl; -use presets::erc721::ERC721::ERC721MetadataImpl; -use presets::erc721::ERC721::InternalImpl; -use presets::erc721::ERC721::WorldInteractionsImpl; -use presets::erc721::ERC721::{Approval, ApprovalForAll, Transfer}; -use presets::erc721::ERC721; -use presets::erc721::models::{ +use token::erc721::ERC721::ERC721Impl; +use token::erc721::ERC721::ERC721CamelOnlyImpl; +use token::erc721::ERC721::ERC721MetadataImpl; +use token::erc721::ERC721::InternalImpl; +use token::erc721::ERC721::WorldInteractionsImpl; +use token::erc721::ERC721::{Approval, ApprovalForAll, Transfer}; +use token::erc721::ERC721; +use token::erc721::models::{ ERC721Meta, erc_721_meta, ERC721OperatorApproval, erc_721_operator_approval, ERC721Owner, erc_721_owner, ERC721Balance, erc_721_balance, ERC721TokenApproval, erc_721_token_approval }; -use presets::erc721::ERC721::_worldContractMemberStateTrait; +use token::erc721::ERC721::_worldContractMemberStateTrait; // // Setup diff --git a/token/src/lib.cairo b/token/src/lib.cairo new file mode 100644 index 00000000..bc0ed295 --- /dev/null +++ b/token/src/lib.cairo @@ -0,0 +1,32 @@ +mod erc20 { + mod interface; + mod models; + mod erc20; + use erc20::ERC20; + #[cfg(test)] + mod tests; +} + +mod erc721 { + mod interface; + mod models; + mod erc721; + use erc721::ERC721; + #[cfg(test)] + mod tests; +} + +mod erc1155 { + mod interface; + mod models; + mod erc1155; + use erc1155::ERC1155; + #[cfg(test)] + mod tests; +} + +#[cfg(test)] +mod tests { + mod constants; + mod utils; +} diff --git a/presets/src/tests/constants.cairo b/token/src/tests/constants.cairo similarity index 100% rename from presets/src/tests/constants.cairo rename to token/src/tests/constants.cairo diff --git a/presets/src/tests/test_erc1155.cairo b/token/src/tests/test_erc1155.cairo similarity index 100% rename from presets/src/tests/test_erc1155.cairo rename to token/src/tests/test_erc1155.cairo diff --git a/presets/src/tests/test_erc721.cairo b/token/src/tests/test_erc721.cairo similarity index 100% rename from presets/src/tests/test_erc721.cairo rename to token/src/tests/test_erc721.cairo diff --git a/presets/src/tests/utils.cairo b/token/src/tests/utils.cairo similarity index 100% rename from presets/src/tests/utils.cairo rename to token/src/tests/utils.cairo From 11b8c89d208991eaccb29935427b046142082af8 Mon Sep 17 00:00:00 2001 From: bal7hazar Date: Tue, 28 Nov 2023 19:57:43 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=94=A5=20Remove=20dead=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- token/src/tests/test_erc1155.cairo | 629 --------------------- token/src/tests/test_erc721.cairo | 862 ----------------------------- 2 files changed, 1491 deletions(-) delete mode 100644 token/src/tests/test_erc1155.cairo delete mode 100644 token/src/tests/test_erc721.cairo diff --git a/token/src/tests/test_erc1155.cairo b/token/src/tests/test_erc1155.cairo deleted file mode 100644 index 5ce73b82..00000000 --- a/token/src/tests/test_erc1155.cairo +++ /dev/null @@ -1,629 +0,0 @@ -use zeroable::Zeroable; -use traits::{Into, Default, IndexView}; -use option::OptionTrait; -use array::ArrayTrait; -use serde::Serde; -use starknet::ContractAddress; -use starknet::testing::set_contract_address; - -use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; - -use dojo_erc::tests::test_utils::impersonate; -use dojo_erc::tests::test_erc1155_utils::{ - spawn_world, deploy_erc1155, deploy_default, deploy_testcase1, ZERO, USER1, USER2, DEPLOYER, - PROXY -}; - -use dojo_erc::erc165::interface::IERC165_ID; -use dojo_erc::erc1155::interface::{ - IERC1155A, IERC1155ADispatcher, IERC1155ADispatcherTrait, IERC1155_ID, IERC1155_METADATA_ID, - IERC1155_RECEIVER_ID -}; - -use dojo_erc::erc1155::erc1155::ERC1155::{Event, TransferSingle, TransferBatch, ApprovalForAll}; - - -#[test] -#[available_gas(30000000)] -fn test_deploy() { - let world = spawn_world(DEPLOYER()); - let erc1155_address = deploy_erc1155(world, DEPLOYER(), 'uri', 'seed-42'); - let erc1155 = IERC1155ADispatcher { contract_address: erc1155_address }; - assert(erc1155.owner() == DEPLOYER(), 'invalid owner'); -} - -#[test] -#[available_gas(30000000)] -fn test_deploy_default() { - let (world, erc1155) = deploy_default(); - assert(erc1155.owner() == DEPLOYER(), 'invalid owner'); -} - - -// -// supports_interface -// - -#[test] -#[available_gas(30000000)] -fn test_should_support_interfaces() { - let (world, erc1155) = deploy_default(); - - assert(erc1155.supports_interface(IERC165_ID) == true, 'should support erc165'); - assert(erc1155.supports_interface(IERC1155_ID) == true, 'should support erc1155'); - assert( - erc1155.supports_interface(IERC1155_METADATA_ID) == true, 'should support erc1155_metadata' - ); -} - -// -// uri -// - -#[test] -#[available_gas(30000000)] -fn test_uri() { - let (world, erc1155) = deploy_default(); - assert(erc1155.uri(64) == 'uri', 'invalid uri'); -} - - -// -// behaves like an ERC1155 -// - -// -// balance_of -// -#[test] -#[available_gas(30000000)] -#[should_panic(expected: ('ERC1155: invalid owner address', 'ENTRYPOINT_FAILED',))] -fn test_balance_of_zero_address() { - //reverts when queried about the zero address - - let (world, erc1155) = deploy_default(); - erc1155.balance_of(ZERO(), 0); // should panic -} - -#[test] -#[available_gas(30000000)] -fn test_balance_of_empty_balance() { - // when accounts don't own tokens - // returns zero for given addresses - let (world, erc1155) = deploy_default(); - assert(erc1155.balance_of(USER1(), 0) == 0, 'should be 0'); - assert(erc1155.balance_of(USER1(), 69) == 0, 'should be 0'); - assert(erc1155.balance_of(USER2(), 0) == 0, 'should be 0'); -} - -#[test] -#[available_gas(30000000)] -fn test_balance_with_tokens() { - // when accounts own some tokens - // returns the amount of tokens owned by the given addresses - let (world, erc1155) = deploy_default(); - - erc1155.mint(USER1(), 0, 1, array![]); - erc1155.mint(USER1(), 69, 42, array![]); - erc1155.mint(USER2(), 69, 5, array![]); - - assert(erc1155.balance_of(USER1(), 0) == 1, 'should be 1'); - assert(erc1155.balance_of(USER1(), 69) == 42, 'should be 42'); - assert(erc1155.balance_of(USER2(), 69) == 5, 'should be 5'); -} - -// -// balance_of_batch -// - -#[test] -#[available_gas(30000000)] -#[should_panic(expected: ('ERC1155: invalid length', 'ENTRYPOINT_FAILED',))] -fn test_balance_of_batch_with_invalid_input() { - // reverts when input arrays don't match up - let (world, erc1155) = deploy_default(); - erc1155.balance_of_batch(array![USER1(), USER2()], array![0]); - erc1155.balance_of_batch(array![USER1()], array![0, 1, 2]); -} - -#[test] -#[available_gas(30000000)] -#[should_panic(expected: ('ERC1155: invalid owner address', 'ENTRYPOINT_FAILED',))] -fn test_balance_of_batch_address_zero() { - // reverts when input arrays don't match up - let (world, erc1155) = deploy_default(); - erc1155.balance_of_batch(array![USER1(), ZERO()], array![0, 1]); -} - -#[test] -#[available_gas(30000000)] -fn test_balance_of_batch_empty_account() { - // when accounts don't own tokens - // returns zeros for each account - let (world, erc1155) = deploy_default(); - let balances = erc1155.balance_of_batch(array![USER1(), USER1(), USER1()], array![0, 1, 5]); - let bals = @balances; - assert(balances.len() == 3, 'should be 3'); - assert(bals[0] == @0_u256, 'should be 0'); - assert(bals[1] == @0_u256, 'should be 0'); - assert(bals[2] == @0_u256, 'should be 0'); -} - -#[test] -#[available_gas(30000000)] -fn test_balance_of_batch_with_tokens() { - // when accounts own some tokens - // returns amounts owned by each account in order passed - let (world, erc1155) = deploy_default(); - - erc1155.mint(USER1(), 0, 1, array![]); - erc1155.mint(USER1(), 69, 42, array![]); - erc1155.mint(USER2(), 69, 2, array![]); - - let balances = erc1155.balance_of_batch(array![USER1(), USER1(), USER2()], array![0, 69, 69]); - let bals = @balances; - assert(balances.len() == 3, 'should be 3'); - assert(bals[0] == @1_u256, 'should be 1'); - assert(bals[1] == @42_u256, 'should be 42'); - assert(bals[2] == @2_u256, 'should be 2'); -} - -#[test] -#[available_gas(30000000)] -fn test_balance_of_batch_with_tokens_2() { - // when accounts own some tokens - // returns multiple times the balance of the same address when asked - let (world, erc1155) = deploy_default(); - - erc1155.mint(USER1(), 0, 1, array![]); - erc1155.mint(USER2(), 69, 2, array![]); - - let balances = erc1155.balance_of_batch(array![USER1(), USER2(), USER1()], array![0, 69, 0]); - let bals = @balances; - assert(balances.len() == 3, 'should be 3'); - assert(bals[0] == @1_u256, 'should be 1'); - assert(bals[1] == @2_u256, 'should be 2'); - assert(bals[2] == @1_u256, 'should be 1'); -} - - -// -// balance_of_batch -// - -#[test] -#[available_gas(30000000)] -fn test_set_approval_for_all() { - // sets approval status which can be queried via is_approved_for_all - let (world, erc1155) = deploy_default(); - impersonate(USER1()); - - erc1155.set_approval_for_all(PROXY(), true); - assert(erc1155.is_approved_for_all(USER1(), PROXY()) == true, 'should be true'); -} - -#[test] -#[available_gas(30000000)] -fn test_set_approval_for_all_emit_event() { - // set_approval_for_all emits ApprovalForAll event - let (world, erc1155) = deploy_default(); - impersonate(USER1()); - - erc1155.set_approval_for_all(PROXY(), true); - - // ApprovalForAll - assert( - @starknet::testing::pop_log(erc1155.contract_address) - .unwrap() == @Event::ApprovalForAll( - ApprovalForAll { owner: USER1(), operator: PROXY(), approved: true } - ), - 'invalid ApprovalForAll event' - ); -} - - -#[test] -#[available_gas(30000000)] -fn test_set_unset_approval_for_all() { - // sets approval status which can be queried via is_approved_for_all - let (world, erc1155) = deploy_default(); - impersonate(USER1()); - - erc1155.set_approval_for_all(PROXY(), true); - assert(erc1155.is_approved_for_all(USER1(), PROXY()) == true, 'should be true'); - erc1155.set_approval_for_all(PROXY(), false); - assert(erc1155.is_approved_for_all(USER1(), PROXY()) == false, 'should be false'); -} - -#[test] -#[available_gas(30000000)] -#[should_panic()] -fn test_set_approval_for_all_on_self() { - // reverts if attempting to approve self as an operator - let (world, erc1155) = deploy_default(); - impersonate(USER1()); - - erc1155.set_approval_for_all(USER1(), true); // should panic -} - -// -// safe_transfer_from -// - -#[test] -#[available_gas(30000000)] -#[should_panic()] -fn test_safe_transfer_from_more_than_balance() { - // reverts when transferring more than balance - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER1()); - - erc1155.safe_transfer_from(USER1(), USER2(), 1, 999, array![]); // should panic -} - -#[test] -#[available_gas(30000000)] -#[should_panic()] -fn test_safe_transfer_to_zero() { - // reverts when transferring to zero address - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER1()); - - erc1155.safe_transfer_from(USER1(), ZERO(), 1, 1, array![]); // should panic -} - -#[test] -#[available_gas(50000000)] -fn test_safe_transfer_debit_sender() { - // debits transferred balance from sender - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER1()); - - let balance_before = erc1155.balance_of(USER1(), 1); - erc1155.safe_transfer_from(USER1(), USER2(), 1, 1, array![]); - let balance_after = erc1155.balance_of(USER1(), 1); - - assert(balance_after == balance_before - 1, 'invalid balance after'); -} - -#[test] -#[available_gas(50000000)] -fn test_safe_transfer_credit_receiver() { - // credits transferred balance to receiver - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER1()); - - let balance_before = erc1155.balance_of(USER2(), 1); - erc1155.safe_transfer_from(USER1(), USER2(), 1, 1, array![]); - let balance_after = erc1155.balance_of(USER2(), 1); - - assert(balance_after == balance_before + 1, 'invalid balance after'); -} - -#[test] -#[available_gas(50000000)] -fn test_safe_transfer_preserve_existing_balances() { - // preserves existing balances which are not transferred by multiTokenHolder - let (world, erc1155) = deploy_testcase1(); - - // impersonate user1 - impersonate(USER1()); - - let balance_before_2 = erc1155.balance_of(USER2(), 2); - let balance_before_3 = erc1155.balance_of(USER2(), 3); - erc1155.safe_transfer_from(USER1(), USER2(), 1, 1, array![]); - let balance_after_2 = erc1155.balance_of(USER2(), 2); - let balance_after_3 = erc1155.balance_of(USER2(), 3); - - assert(balance_after_2 == balance_before_2, 'should be equal'); - assert(balance_after_3 == balance_before_3, 'should be equal'); -} - -#[test] -#[available_gas(30000000)] -#[should_panic()] -fn test_safe_transfer_from_unapproved_operator() { - // when called by an operator on behalf of the multiTokenHolder - // when operator is not approved by multiTokenHolder - - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER2()); - - erc1155.safe_transfer_from(USER1(), USER2(), 1, 1, array![]); // should panic -} - -#[test] -#[available_gas(50000000)] -fn test_safe_transfer_from_approved_operator() { - // when called by an operator on behalf of the multiTokenHolder - // when operator is approved by multiTokenHolder - let (world, erc1155) = deploy_testcase1(); - - impersonate(PROXY()); - - let balance_before = erc1155.balance_of(USER1(), 1); - erc1155.safe_transfer_from(USER1(), USER2(), 1, 2, array![]); - let balance_after = erc1155.balance_of(USER1(), 1); - - assert(balance_after == balance_before - 2, 'invalid balance'); -} - -#[test] -#[available_gas(50000000)] -fn test_safe_transfer_from_approved_operator_preserve_operator_balance() { - // when called by an operator on behalf of the multiTokenHolder - // preserves operator's balances not involved in the transfer - let (world, erc1155) = deploy_testcase1(); - - impersonate(PROXY()); - - let balance_before_1 = erc1155.balance_of(PROXY(), 1); - let balance_before_2 = erc1155.balance_of(PROXY(), 2); - let balance_before_3 = erc1155.balance_of(PROXY(), 3); - erc1155.safe_transfer_from(USER1(), USER2(), 1, 2, array![]); - let balance_after_1 = erc1155.balance_of(PROXY(), 1); - let balance_after_2 = erc1155.balance_of(PROXY(), 2); - let balance_after_3 = erc1155.balance_of(PROXY(), 3); - - assert(balance_before_1 == balance_after_1, 'should be equal'); - assert(balance_before_2 == balance_after_2, 'should be equal'); - assert(balance_before_3 == balance_after_3, 'should be equal'); -} - - -#[test] -#[available_gas(50000000)] -#[should_panic] -fn test_safe_transfer_from_zero_address() { - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER1()); - - erc1155.safe_transfer_from(ZERO(), USER1(), 1, 1, array![]); -} - -// -// safe_batch_transfer_from -// - -#[test] -#[available_gas(50000000)] -#[should_panic] -fn test_safe_batch_transfer_from_more_than_balance() { - // reverts when transferring amount more than any of balances - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER1()); - - erc1155 - .safe_batch_transfer_from(USER1(), USER2(), array![1, 2, 3], array![1, 999, 1], array![]); -} - - -#[test] -#[available_gas(50000000)] -#[should_panic] -fn test_safe_batch_transfer_from_mismatching_array_len() { - // reverts when ids array length doesn't match amounts array length - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER1()); - - erc1155.safe_batch_transfer_from(USER1(), USER2(), array![1, 2, 3], array![1, 1], array![]); -} - - -#[test] -#[available_gas(50000000)] -#[should_panic] -fn test_safe_batch_transfer_from_to_zero_address() { - // reverts when transferring to zero address - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER1()); - - erc1155.safe_batch_transfer_from(USER1(), ZERO(), array![1, 2], array![1, 1], array![]); -} - - -#[test] -#[available_gas(60000000)] -fn test_safe_batch_transfer_from_debits_sender() { - // debits transferred balances from sender - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER1()); - - let balance_before_1 = erc1155.balance_of(USER1(), 1); - let balance_before_2 = erc1155.balance_of(USER1(), 2); - let balance_before_3 = erc1155.balance_of(USER1(), 3); - erc1155 - .safe_batch_transfer_from(USER1(), USER2(), array![1, 2, 3], array![1, 10, 20], array![]); - let balance_after_1 = erc1155.balance_of(USER1(), 1); - let balance_after_2 = erc1155.balance_of(USER1(), 2); - let balance_after_3 = erc1155.balance_of(USER1(), 3); - - assert(balance_before_1 - 1 == balance_after_1, 'invalid balance'); - assert(balance_before_2 - 10 == balance_after_2, 'invalid balance'); - assert(balance_before_3 - 20 == balance_after_3, 'invalid balance'); -} - - -#[test] -#[available_gas(60000000)] -fn test_safe_batch_transfer_from_credits_recipient() { - // credits transferred balances to receiver - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER1()); - - let balance_before_1 = erc1155.balance_of(USER2(), 1); - let balance_before_2 = erc1155.balance_of(USER2(), 2); - let balance_before_3 = erc1155.balance_of(USER2(), 3); - erc1155 - .safe_batch_transfer_from(USER1(), USER2(), array![1, 2, 3], array![1, 10, 20], array![]); - let balance_after_1 = erc1155.balance_of(USER2(), 1); - let balance_after_2 = erc1155.balance_of(USER2(), 2); - let balance_after_3 = erc1155.balance_of(USER2(), 3); - - assert(balance_before_1 + 1 == balance_after_1, 'invalid balance'); - assert(balance_before_2 + 10 == balance_after_2, 'invalid balance'); - assert(balance_before_1 + 20 == balance_after_3, 'invalid balance'); -} - - -#[test] -#[available_gas(50000000)] -#[should_panic] -fn test_safe_batch_transfer_from_unapproved_operator() { - // when called by an operator on behalf of the multiTokenHolder - // when operator is not approved by multiTokenHolder - - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER2()); - - erc1155.safe_batch_transfer_from(USER1(), USER2(), array![1, 2], array![1, 10], array![]); -} - -#[test] -#[available_gas(60000000)] -fn test_safe_batch_transfer_from_approved_operator_preserve_operator_balance() { - // when called by an operator on behalf of the multiTokenHolder - // preserves operator's balances not involved in the transfer - - let (world, erc1155) = deploy_testcase1(); - - impersonate(PROXY()); - - let balance_before_1 = erc1155.balance_of(PROXY(), 1); - let balance_before_2 = erc1155.balance_of(PROXY(), 2); - let balance_before_3 = erc1155.balance_of(PROXY(), 3); - - erc1155 - .safe_batch_transfer_from(USER1(), USER2(), array![1, 2, 3], array![1, 10, 20], array![]); - - let balance_after_1 = erc1155.balance_of(PROXY(), 1); - let balance_after_2 = erc1155.balance_of(PROXY(), 2); - let balance_after_3 = erc1155.balance_of(PROXY(), 3); - - assert(balance_before_1 == balance_after_1, 'should be equal'); - assert(balance_before_2 == balance_after_2, 'should be equal'); - assert(balance_before_3 == balance_after_3, 'should be equal'); -} - -#[test] -#[available_gas(50000000)] -#[should_panic] -fn test_safe_batch_transfer_from_zero_address() { - let (world, erc1155) = deploy_testcase1(); - - impersonate(USER1()); - - erc1155.safe_batch_transfer_from(ZERO(), USER1(), array![1, 2], array![1, 1], array![]); -} - - -#[test] -#[available_gas(50000000)] -fn test_safe_batch_transfer_emit_transfer_batch_event() { - let (world, erc1155) = deploy_default(); - - // user1 token_id 1 x 10 - erc1155.mint(USER1(), 1, 10, array![]); - // user1 token_id 2 x 20 - erc1155.mint(USER1(), 2, 20, array![]); - - impersonate(USER1()); - - erc1155.safe_batch_transfer_from(USER1(), USER2(), array![1, 2], array![1, 10], array![]); - - let _: Event = starknet::testing::pop_log(erc1155.contract_address) - .unwrap(); // unpop erc1155.mint(USER1(), 1, 10, array![]); - let _: Event = starknet::testing::pop_log(erc1155.contract_address) - .unwrap(); // unpop erc1155.mint(USER1(), 2, 20, array![]); - - // TransferBatch - assert( - @starknet::testing::pop_log(erc1155.contract_address) - .unwrap() == @Event::TransferBatch( - TransferBatch { - operator: USER1(), - from: USER1(), - to: USER2(), - ids: array![1, 2], - values: array![1, 10] - } - ), - 'invalid TransferBatch event' - ); -} - - -// -// burn -// - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_burn_non_existing_token_id() { - //reverts when burning a non-existent token id - let (world, erc1155) = deploy_default(); - - impersonate(USER1()); - erc1155.burn(USER1(), 69, 1); // should panic -} - - -#[test] -#[available_gas(90000000)] -fn test_burn_emit_transfer_single_event() { - // burn should emit event - let (world, erc1155) = deploy_default(); - - erc1155.mint(USER1(), 69, 5, array![]); - assert(erc1155.balance_of(USER1(), 69) == 5, 'invalid balance'); - - impersonate(USER1()); - - erc1155.burn(USER1(), 69, 1); - assert(erc1155.balance_of(USER1(), 69) == 4, 'invalid balance'); - - let _: Event = starknet::testing::pop_log(erc1155.contract_address) - .unwrap(); // unpop erc1155.mint(USER1(), 69,5,array![]) - - // TransferSingle - assert( - @starknet::testing::pop_log(erc1155.contract_address) - .unwrap() == @Event::TransferSingle( - TransferSingle { operator: USER1(), from: USER1(), to: ZERO(), id: 69, value: 1 } - ), - 'invalid TransferSingle event' - ); -} - - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_burn_more_than_owned() { - // reverts when burning more tokens than owned - let (world, erc1155) = deploy_default(); - erc1155.mint(USER1(), 69, 10, array![]); - - impersonate(USER1()); - - erc1155.burn(USER1(), 69, 1); - erc1155.burn(USER1(), 69, 10); // should panic -} -// TODO : to be continued - -// TODO : add test if we support IERC1155Receiver - - diff --git a/token/src/tests/test_erc721.cairo b/token/src/tests/test_erc721.cairo deleted file mode 100644 index fc23abc4..00000000 --- a/token/src/tests/test_erc721.cairo +++ /dev/null @@ -1,862 +0,0 @@ -use core::zeroable::Zeroable; -use core::traits::{Into, Default}; -use array::ArrayTrait; -use serde::Serde; -use starknet::ContractAddress; -use starknet::testing::set_contract_address; -use option::OptionTrait; - -use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; - -use dojo_erc::tests::test_utils::impersonate; -use dojo_erc::tests::test_erc721_utils::{ - spawn_world, deploy_erc721, deploy_default, deploy_testcase1, USER1, USER2, USER3, DEPLOYER, - ZERO, PROXY -}; - - -use dojo_erc::erc165::interface::IERC165_ID; -use dojo_erc::erc721::interface::{ - IERC721, IERC721ADispatcher, IERC721ADispatcherTrait, IERC721_ID, IERC721_METADATA_ID -}; -use dojo_erc::erc721::erc721::ERC721::{Event, Transfer, Approval, ApprovalForAll}; -// actually it's possible to mint -> burn -> mint -> ... -// todo : add Minted component to keep track of minted ids - -#[test] -#[available_gas(30000000)] -fn test_deploy() { - let world = spawn_world(DEPLOYER()); - let erc721_address = deploy_erc721(world, DEPLOYER(), 'name', 'symbol', 'uri', 'seed-42'); - let erc721 = IERC721ADispatcher { contract_address: erc721_address }; - - assert(erc721.owner() == DEPLOYER(), 'invalid owner'); - assert(erc721.name() == 'name', 'invalid name'); - assert(erc721.symbol() == 'symbol', 'invalid symbol'); -} - - -#[test] -#[available_gas(30000000)] -fn test_deploy_default() { - let (world, erc721) = deploy_default(); - assert(erc721.name() == 'name', 'invalid name'); -} - -// -// supports_interface -// - -#[test] -#[available_gas(30000000)] -fn test_should_support_interfaces() { - let (world, erc721) = deploy_default(); - - assert(erc721.supports_interface(IERC165_ID) == true, 'should support erc165'); - assert(erc721.supports_interface(IERC721_ID) == true, 'should support erc721'); - assert( - erc721.supports_interface(IERC721_METADATA_ID) == true, 'should support erc721_metadata' - ); -} - - -// -// behaves like an ERC721 -// - -// -// balance_of -// - -use debug::PrintTrait; - -#[test] -#[available_gas(60000000)] -fn test_balance_of_with_tokens() { - // returns the amount of tokens owned by the given address - - let (world, erc721) = deploy_testcase1(); - assert(erc721.balance_of(USER1()) == 3, 'should be 3'); - assert(erc721.balance_of(PROXY()) == 4, 'should be 4'); -} - -#[test] -#[available_gas(60000000)] -fn test_balance_of_with_no_tokens() { - // when the given address does not own any tokens - - let (world, erc721) = deploy_testcase1(); - assert(erc721.balance_of(USER3()) == 0, 'should be 0'); -} - - -#[test] -#[available_gas(50000000)] -#[should_panic] -fn test_balance_of_zero_address() { - // when querying the zero address - - let (world, erc721) = deploy_testcase1(); - erc721.balance_of(ZERO()); -} - -// -// owner_of -// - -#[test] -#[available_gas(90000000)] -fn test_owner_of_existing_id() { - // when the given token ID was tracked by this token = for existing id - - let (world, erc721) = deploy_testcase1(); - assert(erc721.owner_of(1) == USER1(), 'should be user1'); - assert(erc721.owner_of(2) == USER1(), 'should be user1'); - assert(erc721.owner_of(3) == USER1(), 'should be user1'); - - assert(erc721.owner_of(10) == PROXY(), 'should be proxy'); - assert(erc721.owner_of(11) == PROXY(), 'should be proxy'); - assert(erc721.owner_of(12) == PROXY(), 'should be proxy'); - assert(erc721.owner_of(13) == PROXY(), 'should be proxy'); -} - - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_owner_of_non_existing_id() { - // when the given token ID was not tracked by this token = non existing id - - let (world, erc721) = deploy_testcase1(); - let owner_of_0 = erc721.owner_of(0); // should panic -} - -// -// transfers -// - -#[test] -#[available_gas(90000000)] -fn test_transfer_ownership() { - // transfers the ownership of the given token ID to the given address - - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - let owner_of_1 = erc721.owner_of(1); - // transfer token_id 1 to user2 - erc721.transfer(USER2(), 1); - assert(erc721.owner_of(1) == USER2(), 'invalid owner'); -} - -#[test] -#[available_gas(90000000)] -fn test_transfer_event() { - // emits a Transfer event - - let (world, erc721) = deploy_default(); - - // mint - erc721.mint(USER1(), 42); - - impersonate(USER1()); - - // transfer token_id 1 to user2 - erc721.transfer(USER2(), 42); - - impersonate(USER2()); - erc721.burn(42); - - // mint - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::Transfer(Transfer { from: ZERO(), to: USER1(), token_id: 42 }), - 'invalid Transfer event' - ); - // transfer - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::Transfer(Transfer { from: USER1(), to: USER2(), token_id: 42 }), - 'invalid Transfer event' - ); - // burn - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::Transfer(Transfer { from: USER2(), to: ZERO(), token_id: 42 }), - 'invalid Transfer event' - ); -} - - -#[test] -#[available_gas(90000000)] -fn test_transfer_clear_approval() { - // clears the approval for the token ID - - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - erc721.approve(PROXY(), 1); - assert(erc721.get_approved(1) == PROXY(), 'should be proxy'); - - // transfer token_id 1 to user2 - erc721.transfer(USER2(), 1); - assert(erc721.get_approved(1).is_zero(), 'should be zero'); -} - -#[test] -#[available_gas(90000000)] -fn test_transfer_adjusts_owners_balances() { - // adjusts owners balances - - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - let balance_user1_before = erc721.balance_of(USER1()); - let balance_user2_before = erc721.balance_of(USER2()); - - // transfer token_id 1 to user2 - erc721.transfer(USER2(), 1); - - let balance_user1_after = erc721.balance_of(USER1()); - let balance_user2_after = erc721.balance_of(USER2()); - - assert(balance_user1_after == balance_user1_before - 1, 'invalid user1 balance'); - assert(balance_user2_after == balance_user2_before + 1, 'invalid user2 balance'); -} - - -#[test] -#[available_gas(90000000)] -fn test_transfer_from_approved() { - // when called by the approved individual - - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - //user1 approve user2 for token_id 2 - erc721.approve(USER2(), 2); - - impersonate(USER2()); - - erc721.transfer_from(USER1(), USER2(), 2); - assert(erc721.owner_of(2) == USER2(), 'invalid owner'); -} - -#[test] -#[available_gas(90000000)] -fn test_transfer_from_approved_operator() { - // when called by the operator - - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - //user1 set_approval_for_all for proxy - erc721.set_approval_for_all(PROXY(), true); - - impersonate(PROXY()); - - erc721.transfer_from(USER1(), USER2(), 2); - assert(erc721.owner_of(2) == USER2(), 'invalid owner'); -} - -#[test] -#[available_gas(90000000)] -fn test_transfer_from_owner_without_approved() { - // when called by the owner without an approved user - - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - erc721.approve(ZERO(), 2); - - erc721.transfer_from(USER1(), USER2(), 2); - assert(erc721.owner_of(2) == USER2(), 'invalid owner'); -} - - -#[test] -#[available_gas(90000000)] -fn test_transfer_to_owner() { - // when sent to the owner - - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - let balance_before = erc721.balance_of(USER1()); - - assert(erc721.owner_of(3) == USER1(), 'invalid owner'); - erc721.transfer(USER1(), 3); - - // keeps ownership of the token - assert(erc721.owner_of(3) == USER1(), 'invalid owner'); - - // clears the approval for the token ID - assert(erc721.get_approved(3) == ZERO(), 'invalid approved'); - - //emits only a transfer event : cumbersome to test with pop_log - - //keeps the owner balance - let balance_after = erc721.balance_of(USER1()); - assert(balance_before == balance_after, 'invalid balance') -} - - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_transfer_when_previous_owner_is_incorrect() { - // when the address of the previous owner is incorrect - - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - //user2 owner token_id 10 - erc721.transfer_from(USER1(), PROXY(), 10); // should panic -} - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_transfer_when_sender_not_authorized() { - // when the sender is not authorized for the token id - let (world, erc721) = deploy_testcase1(); - - impersonate(PROXY()); - - //proxy is not authorized for USER2 - erc721.transfer_from(USER2(), PROXY(), 20); // should panic -} - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_transfer_when_token_id_doesnt_exists() { - // when the sender is not authorized for the token id - let (world, erc721) = deploy_testcase1(); - - impersonate(PROXY()); - - //proxy is authorized for USER1 but token_id 50 doesnt exists - erc721.transfer_from(USER1(), PROXY(), 50); // should panic -} - - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_transfer_to_address_zero() { - // when the address to transfer the token to is the zero address - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - erc721.transfer(ZERO(), 1); // should panic -} - -// -// approval -// - -// when clearing approval - -#[test] -#[available_gas(90000000)] -fn test_approval_when_clearing_with_prior_approval() { - // -when there was a prior approval - let (world, erc721) = deploy_default(); - - erc721.mint(USER1(), 42); - - impersonate(USER1()); - - erc721.approve(PROXY(), 42); - - //revoke approve - erc721.approve(ZERO(), 42); - - // clears approval for the token - assert(erc721.get_approved(42) == ZERO(), 'invalid approved'); - - // emits an approval event - let _: Event = starknet::testing::pop_log(erc721.contract_address).unwrap(); // unpop mint - let _: Event = starknet::testing::pop_log(erc721.contract_address) - .unwrap(); // unpop approve PROXY - - // approve ZERO - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::Approval(Approval { owner: USER1(), to: ZERO(), token_id: 42 }), - 'invalid Approval event' - ); -} - -#[test] -#[available_gas(90000000)] -fn test_approval_when_clearing_without_prior_approval() { - // when clearing approval - // -when there was no prior approval - let (world, erc721) = deploy_default(); - - erc721.mint(USER1(), 42); - - impersonate(USER1()); - - //revoke approve - erc721.approve(ZERO(), 42); - - // updates approval for the token - assert(erc721.get_approved(42) == ZERO(), 'invalid approved'); - - let _: Event = starknet::testing::pop_log(erc721.contract_address).unwrap(); // unpop mint - - // approve ZERO - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::Approval(Approval { owner: USER1(), to: ZERO(), token_id: 42 }), - 'invalid Approval event' - ); -} - - -// when approving a non-zero address - -#[test] -#[available_gas(90000000)] -fn test_approval_non_zero_address_with_prior_approval() { - // -when there was a prior approval - let (world, erc721) = deploy_default(); - - erc721.mint(USER1(), 42); - - impersonate(USER1()); - erc721.approve(PROXY(), 42); - - // user1 approves user3 - erc721.approve(USER3(), 42); - - // set approval for the token - assert(erc721.get_approved(42) == USER3(), 'invalid approved'); - - // emits an approval event - let _: Event = starknet::testing::pop_log(erc721.contract_address).unwrap(); // unpop mint - let _: Event = starknet::testing::pop_log(erc721.contract_address) - .unwrap(); // unpop approve PROXY - - // approve USER3 - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::Approval(Approval { owner: USER1(), to: USER3(), token_id: 42 }), - 'invalid Approval event' - ); -} - -#[test] -#[available_gas(90000000)] -fn test_approval_non_zero_address_with_no_prior_approval() { - // -when there was no prior approval - let (world, erc721) = deploy_default(); - - erc721.mint(USER1(), 42); - - impersonate(USER1()); - - // user1 approves user3 - erc721.approve(USER3(), 42); - - // set approval for the token - assert(erc721.get_approved(42) == USER3(), 'invalid approved'); - - // emits an approval event - let _: Event = starknet::testing::pop_log(erc721.contract_address).unwrap(); // unpop mint - - // approve USER3 - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::Approval(Approval { owner: USER1(), to: USER3(), token_id: 42 }), - 'invalid Approval event' - ); -} - - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_approval_self_approve() { - // when the address that receives the approval is the owner - let (world, erc721) = deploy_default(); - - erc721.mint(USER1(), 42); - - impersonate(USER1()); - - // user1 approves user1 - erc721.approve(USER1(), 42); // should panic -} - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_approval_not_owned() { - // when the sender does not own the given token ID - - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - // user1 approves user2 for token 20 - erc721.approve(USER2(), 20); // should panic -} - - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_approval_from_approved_sender() { - // when the sender is approved for the given token ID - - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - // user1 approve user3 - erc721.approve(USER3(), 1); - - impersonate(USER3()); - - // (ERC721: approve caller is not token owner or approved for all) - erc721.approve(USER2(), 1); // should panic -} - - -#[test] -#[available_gas(90000000)] -fn test_approval_from_approved_operator() { - // when the sender is an operator - let (world, erc721) = deploy_default(); - - erc721.mint(USER1(), 50); - - impersonate(USER1()); - - erc721.set_approval_for_all(PROXY(), true); - - impersonate(PROXY()); - - // proxy approves user2 for token 20 - erc721.approve(USER2(), 50); - - assert(erc721.get_approved(50) == USER2(), 'invalid approval'); - - let _: Event = starknet::testing::pop_log(erc721.contract_address).unwrap(); // unpop mint - let _: Event = starknet::testing::pop_log(erc721.contract_address) - .unwrap(); // unpop set_approval_for_all - - // approve - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::Approval(Approval { owner: USER1(), to: USER2(), token_id: 50 }), - 'invalid Approval event' - ); -} - - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_approval_unexisting_id() { - // when the given token ID does not exist - let (world, erc721) = deploy_testcase1(); - - impersonate(USER1()); - - // user1 approve user3 - erc721.approve(USER3(), 69); // should panic -} - -// -// approval_for_all -// - -#[test] -#[available_gas(90000000)] -fn test_approval_for_all_operator_is_not_owner_no_operator_approval() { - // when the operator willing to approve is not the owner - // -when there is no operator approval set by the sender - let (world, erc721) = deploy_default(); - - impersonate(USER2()); - - // user2 set_approval_for_all PROXY - erc721.set_approval_for_all(PROXY(), true); - - assert(erc721.is_approved_for_all(USER2(), PROXY()) == true, 'invalid is_approved_for_all'); - - // ApproveForAll - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::ApprovalForAll( - ApprovalForAll { owner: USER2(), operator: PROXY(), approved: true } - ), - 'invalid ApprovalForAll event' - ); -} - -#[test] -#[available_gas(90000000)] -fn test_approval_for_all_operator_is_not_owner_from_not_approved() { - // when the operator willing to approve is not the owner - // -when the operator was set as not approved - let (world, erc721) = deploy_default(); - - impersonate(USER2()); - - erc721.set_approval_for_all(PROXY(), false); - - // user2 set_approval_for_all PROXY - erc721.set_approval_for_all(PROXY(), true); - - assert(erc721.is_approved_for_all(USER2(), PROXY()) == true, 'invalid is_approved_for_all'); - - let _: Event = starknet::testing::pop_log(erc721.contract_address) - .unwrap(); // unpop set_approval_for_all(PROXY(), false) - - // ApproveForAll - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::ApprovalForAll( - ApprovalForAll { owner: USER2(), operator: PROXY(), approved: true } - ), - 'invalid ApprovalForAll event' - ); -} - -#[test] -#[available_gas(90000000)] -fn test_approval_for_all_operator_is_not_owner_can_unset_approval_for_all() { - // when the operator willing to approve is not the owner - // can unset the operator approval - let (world, erc721) = deploy_default(); - - impersonate(USER2()); - - erc721.set_approval_for_all(PROXY(), false); - erc721.set_approval_for_all(PROXY(), true); - assert(erc721.is_approved_for_all(USER2(), PROXY()) == true, 'invalid is_approved_for_all'); - erc721.set_approval_for_all(PROXY(), false); - assert(erc721.is_approved_for_all(USER2(), PROXY()) == false, 'invalid is_approved_for_all'); - - let _: Event = starknet::testing::pop_log(erc721.contract_address) - .unwrap(); // unpop set_approval_for_all(PROXY(), false) - let _: Event = starknet::testing::pop_log(erc721.contract_address) - .unwrap(); // unpop set_approval_for_all(PROXY(), true) - - // ApproveForAll - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::ApprovalForAll( - ApprovalForAll { owner: USER2(), operator: PROXY(), approved: false } - ), - 'invalid ApprovalForAll event' - ); -} - -#[test] -#[available_gas(90000000)] -fn test_approval_for_all_operator_with_operator_already_approved() { - // when the operator willing to approve is not the owner - // when the operator was already approved - let (world, erc721) = deploy_default(); - - impersonate(USER2()); - - erc721.set_approval_for_all(PROXY(), true); - assert(erc721.is_approved_for_all(USER2(), PROXY()) == true, 'invalid is_approved_for_all'); - erc721.set_approval_for_all(PROXY(), true); - assert(erc721.is_approved_for_all(USER2(), PROXY()) == true, 'invalid is_approved_for_all'); - - let _: Event = starknet::testing::pop_log(erc721.contract_address) - .unwrap(); // unpop set_approval_for_all(PROXY(), true) - - // ApproveForAll - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::ApprovalForAll( - ApprovalForAll { owner: USER2(), operator: PROXY(), approved: true } - ), - 'invalid ApprovalForAll event' - ); -} - - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_approval_for_all_with_owner_as_operator() { - // when the operator is the owner - - let (world, erc721) = deploy_default(); - - impersonate(USER1()); - - erc721.set_approval_for_all(USER1(), true); // should panic -} - - -// -// get_approved -// - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_get_approved_unexisting_token() { - let (world, erc721) = deploy_default(); - - erc721.get_approved(420); // should panic -} - - -#[test] -#[available_gas(90000000)] -fn test_get_approved_with_existing_token() { - let (world, erc721) = deploy_default(); - - erc721.mint(USER1(), 420); - assert(erc721.get_approved(420) == ZERO(), 'invalid get_approved'); -} - - -#[test] -#[available_gas(90000000)] -fn test_get_approved_with_existing_token_and_approval() { - let (world, erc721) = deploy_default(); - - erc721.mint(USER1(), 420); - - impersonate(USER1()); - - erc721.approve(PROXY(), 420); - assert(erc721.get_approved(420) == PROXY(), 'invalid get_approved'); -} - -// -// mint -// - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_mint_to_address_zero() { - // reverts with a null destination address - - let (world, erc721) = deploy_default(); - - erc721.mint(ZERO(), 69); // should panic -} - - -#[test] -#[available_gas(90000000)] -fn test_mint() { - // reverts with a null destination address - - let (world, erc721) = deploy_default(); - - erc721.mint(USER1(), 69); - - assert(erc721.balance_of(USER1()) == 1, 'invalid balance'); - - // Transfer - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::Transfer(Transfer { from: ZERO(), to: USER1(), token_id: 69 }), - 'invalid Transfer event' - ); -} - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_mint_existing_token_id() { - // reverts with a null destination address - - let (world, erc721) = deploy_default(); - - erc721.mint(USER1(), 69); - erc721.mint(USER1(), 69); //should panic -} - - -// -// burn -// - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_burn_non_existing_token_id() { - //reverts when burning a non-existent token id - let (world, erc721) = deploy_default(); - erc721.burn(69); // should panic -} - - -#[test] -#[available_gas(90000000)] -fn test_burn_emit_events() { - // burn should emit event - let (world, erc721) = deploy_default(); - - erc721.mint(USER1(), 69); - assert(erc721.balance_of(USER1()) == 1, 'invalid balance'); - - impersonate(USER1()); - - erc721.burn(69); - assert(erc721.balance_of(USER1()) == 0, 'invalid balance'); - - let _: Event = starknet::testing::pop_log(erc721.contract_address) - .unwrap(); // unpop erc721.mint(USER1(), 69) - - // Transfer - assert( - @starknet::testing::pop_log(erc721.contract_address) - .unwrap() == @Event::Transfer(Transfer { from: USER1(), to: ZERO(), token_id: 69 }), - 'invalid Transfer event' - ); -} - - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_burn_same_id_twice() { - // reverts when burning a token id that has been deleted - let (world, erc721) = deploy_default(); - erc721.mint(USER1(), 69); - erc721.burn(69); - erc721.burn(69); // should panic -} - -// -// token_uri -// - -#[test] -#[available_gas(90000000)] -#[should_panic] -fn test_token_uri_for_non_existing_token_id() { - // reverts when queried for non existent token id - let (world, erc721) = deploy_default(); - erc721.token_uri(1234); // should panic -} - From 9896620f902c7f059f551b236fd5a36cbccb1cae Mon Sep 17 00:00:00 2001 From: bal7hazar Date: Tue, 28 Nov 2023 20:22:39 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=E2=9C=A8=20Improve=20interfaces=20and=20ad?= =?UTF-8?q?d=20ABI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- token/src/erc1155/interface.cairo | 63 ++++++++++++++++++++++++ token/src/erc20/erc20.cairo | 5 +- token/src/erc20/interface.cairo | 70 +++++++++++++++++++++++++- token/src/erc20/tests.cairo | 13 ++--- token/src/erc721/interface.cairo | 82 ++++++++++++++++++++++++++++--- 5 files changed, 218 insertions(+), 15 deletions(-) diff --git a/token/src/erc1155/interface.cairo b/token/src/erc1155/interface.cairo index ecce8fb9..e29a6626 100644 --- a/token/src/erc1155/interface.cairo +++ b/token/src/erc1155/interface.cairo @@ -60,3 +60,66 @@ trait IERC1155Metadata { fn symbol(self: @TState) -> felt252; fn uri(self: @TState, token_id: u256) -> felt252; } + +// +// ERC721 ABI +// + +#[starknet::interface] +trait ERC1155ABI { + // IERC1155 + fn balance_of(self: @TState, account: ContractAddress, id: u256) -> u256; + fn balance_of_batch( + self: @TState, accounts: Array, ids: Array + ) -> Array; + fn set_approval_for_all(ref self: TState, operator: ContractAddress, approved: bool); + fn is_approved_for_all( + self: @TState, account: ContractAddress, operator: ContractAddress + ) -> bool; + fn safe_transfer_from( + ref self: TState, + from: ContractAddress, + to: ContractAddress, + id: u256, + amount: u256, + data: Array + ); + fn safe_batch_transfer_from( + ref self: TState, + from: ContractAddress, + to: ContractAddress, + ids: Array, + amounts: Array, + data: Array + ); + + // IERC1155Metadata + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn uri(self: @TState, token_id: u256) -> felt252; + + // IERC1155CamelOnly + fn balanceOf(self: @TState, account: ContractAddress, id: u256) -> u256; + fn balanceOfBatch( + self: @TState, accounts: Array, ids: Array + ) -> Array; + fn setApprovalForAll(ref self: TState, operator: ContractAddress, approved: bool); + fn isApprovedForAll(self: @TState, account: ContractAddress, operator: ContractAddress) -> bool; + fn safeTransferFrom( + ref self: TState, + from: ContractAddress, + to: ContractAddress, + id: u256, + amount: u256, + data: Array + ); + fn safeBatchTransferFrom( + ref self: TState, + from: ContractAddress, + to: ContractAddress, + ids: Array, + amounts: Array, + data: Array + ); +} + diff --git a/token/src/erc20/erc20.cairo b/token/src/erc20/erc20.cairo index 7550d963..ff87bcd5 100644 --- a/token/src/erc20/erc20.cairo +++ b/token/src/erc20/erc20.cairo @@ -63,7 +63,7 @@ mod ERC20 { // #[external(v0)] - impl ERC20Impl of interface::IERC20 { + impl ERC20MetadataImpl of interface::IERC20Metadata { fn name(self: @ContractState) -> felt252 { self.get_meta().name } @@ -75,7 +75,10 @@ mod ERC20 { fn decimals(self: @ContractState) -> u8 { 18 } + } + #[external(v0)] + impl ERC20Impl of interface::IERC20 { fn total_supply(self: @ContractState) -> u256 { self.get_meta().total_supply } diff --git a/token/src/erc20/interface.cairo b/token/src/erc20/interface.cairo index e0778409..89939915 100644 --- a/token/src/erc20/interface.cairo +++ b/token/src/erc20/interface.cairo @@ -2,9 +2,61 @@ use starknet::ContractAddress; #[starknet::interface] trait IERC20 { + fn total_supply(self: @TState) -> u256; + fn balance_of(self: @TState, account: ContractAddress) -> u256; + fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool; + fn transfer_from( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; +} + +#[starknet::interface] +trait IERC20Metadata { fn name(self: @TState) -> felt252; fn symbol(self: @TState) -> felt252; fn decimals(self: @TState) -> u8; +} + +#[starknet::interface] +trait ISafeAllowance { + fn increase_allowance(ref self: TState, spender: ContractAddress, added_value: u256) -> bool; + fn decrease_allowance( + ref self: TState, spender: ContractAddress, subtracted_value: u256 + ) -> bool; +} + +#[starknet::interface] +trait IERC20Camel { + fn totalSupply(self: @TState) -> u256; + fn balanceOf(self: @TState, account: ContractAddress) -> u256; + fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool; + fn transferFrom( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; +} + +#[starknet::interface] +trait IERC20CamelOnly { + fn totalSupply(self: @TState) -> u256; + fn balanceOf(self: @TState, account: ContractAddress) -> u256; + fn transferFrom( + ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; +} + +#[starknet::interface] +trait ISafeAllowanceCamel { + fn increaseAllowance(ref self: TState, spender: ContractAddress, addedValue: u256) -> bool; + fn decreaseAllowance(ref self: TState, spender: ContractAddress, subtractedValue: u256) -> bool; +} + +#[starknet::interface] +trait ERC20ABI { + // IERC20 fn total_supply(self: @TState) -> u256; fn balance_of(self: @TState, account: ContractAddress) -> u256; fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256; @@ -13,12 +65,26 @@ trait IERC20 { ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 ) -> bool; fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool; -} -trait IERC20CamelOnly { + // IERC20Metadata + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn decimals(self: @TState) -> u8; + + // IERC20SafeAllowance + fn increase_allowance(ref self: TState, spender: ContractAddress, added_value: u256) -> bool; + fn decrease_allowance( + ref self: TState, spender: ContractAddress, subtracted_value: u256 + ) -> bool; + + // IERC20CamelOnly fn totalSupply(self: @TState) -> u256; fn balanceOf(self: @TState, account: ContractAddress) -> u256; fn transferFrom( ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256 ) -> bool; + + // IERC20CamelSafeAllowance + fn increaseAllowance(ref self: TState, spender: ContractAddress, addedValue: u256) -> bool; + fn decreaseAllowance(ref self: TState, spender: ContractAddress, subtractedValue: u256) -> bool; } diff --git a/token/src/erc20/tests.cairo b/token/src/erc20/tests.cairo index 7db32972..3f088e4b 100644 --- a/token/src/erc20/tests.cairo +++ b/token/src/erc20/tests.cairo @@ -7,6 +7,7 @@ use token::tests::constants::{ }; use token::erc20::ERC20::Approval; use token::erc20::ERC20::ERC20Impl; +use token::erc20::ERC20::ERC20MetadataImpl; use token::erc20::ERC20::InternalImpl; use token::erc20::ERC20::Transfer; use token::erc20::ERC20; @@ -57,9 +58,9 @@ fn test_initializer() { let (world, mut state) = STATE(); InternalImpl::initializer(ref state, NAME, SYMBOL); - assert(ERC20Impl::name(@state) == NAME, 'Name should be NAME'); - assert(ERC20Impl::symbol(@state) == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC20Impl::decimals(@state) == DECIMALS, 'Decimals should be 18'); + assert(ERC20MetadataImpl::name(@state) == NAME, 'Name should be NAME'); + assert(ERC20MetadataImpl::symbol(@state) == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20MetadataImpl::decimals(@state) == DECIMALS, 'Decimals should be 18'); assert(ERC20Impl::total_supply(@state) == 0, 'Supply should eq 0'); } @@ -74,9 +75,9 @@ fn test_constructor() { assert(ERC20Impl::balance_of(@state, OWNER()) == SUPPLY, 'Should eq inital_supply'); assert(ERC20Impl::total_supply(@state) == SUPPLY, 'Should eq inital_supply'); - assert(ERC20Impl::name(@state) == NAME, 'Name should be NAME'); - assert(ERC20Impl::symbol(@state) == SYMBOL, 'Symbol should be SYMBOL'); - assert(ERC20Impl::decimals(@state) == DECIMALS, 'Decimals should be 18'); + assert(ERC20MetadataImpl::name(@state) == NAME, 'Name should be NAME'); + assert(ERC20MetadataImpl::symbol(@state) == SYMBOL, 'Symbol should be SYMBOL'); + assert(ERC20MetadataImpl::decimals(@state) == DECIMALS, 'Decimals should be 18'); } // diff --git a/token/src/erc721/interface.cairo b/token/src/erc721/interface.cairo index 730ad2e0..d257cc95 100644 --- a/token/src/erc721/interface.cairo +++ b/token/src/erc721/interface.cairo @@ -10,7 +10,6 @@ const IERC721_RECEIVER_ID: felt252 = trait IERC721 { fn balance_of(self: @TState, account: ContractAddress) -> u256; fn owner_of(self: @TState, token_id: u256) -> ContractAddress; - fn transfer_from(ref self: TState, from: ContractAddress, to: ContractAddress, token_id: u256); fn safe_transfer_from( ref self: TState, from: ContractAddress, @@ -18,6 +17,7 @@ trait IERC721 { token_id: u256, data: Span ); + fn transfer_from(ref self: TState, from: ContractAddress, to: ContractAddress, token_id: u256); fn approve(ref self: TState, to: ContractAddress, token_id: u256); fn set_approval_for_all(ref self: TState, operator: ContractAddress, approved: bool); fn get_approved(self: @TState, token_id: u256) -> ContractAddress; @@ -26,11 +26,17 @@ trait IERC721 { ) -> bool; } +#[starknet::interface] +trait IERC721Metadata { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn token_uri(self: @TState, token_id: u256) -> felt252; +} + #[starknet::interface] trait IERC721CamelOnly { fn balanceOf(self: @TState, account: ContractAddress) -> u256; fn ownerOf(self: @TState, tokenId: u256) -> ContractAddress; - fn transferFrom(ref self: TState, from: ContractAddress, to: ContractAddress, tokenId: u256); fn safeTransferFrom( ref self: TState, from: ContractAddress, @@ -38,23 +44,87 @@ trait IERC721CamelOnly { tokenId: u256, data: Span ); + fn transferFrom(ref self: TState, from: ContractAddress, to: ContractAddress, tokenId: u256); fn setApprovalForAll(ref self: TState, operator: ContractAddress, approved: bool); fn getApproved(self: @TState, tokenId: u256) -> ContractAddress; fn isApprovedForAll(self: @TState, owner: ContractAddress, operator: ContractAddress) -> bool; } +#[starknet::interface] +trait IERC721MetadataCamelOnly { + fn tokenURI(self: @TState, tokenId: u256) -> felt252; +} + // -// IERC721Metadata +// ERC721 ABI // #[starknet::interface] -trait IERC721Metadata { +trait ERC721ABI { + // IERC721 + fn balance_of(self: @TState, account: ContractAddress) -> u256; + fn owner_of(self: @TState, token_id: u256) -> ContractAddress; + fn safe_transfer_from( + ref self: TState, + from: ContractAddress, + to: ContractAddress, + token_id: u256, + data: Span + ); + fn transfer_from(ref self: TState, from: ContractAddress, to: ContractAddress, token_id: u256); + fn approve(ref self: TState, to: ContractAddress, token_id: u256); + fn set_approval_for_all(ref self: TState, operator: ContractAddress, approved: bool); + fn get_approved(self: @TState, token_id: u256) -> ContractAddress; + fn is_approved_for_all( + self: @TState, owner: ContractAddress, operator: ContractAddress + ) -> bool; + + // IERC721Metadata fn name(self: @TState) -> felt252; fn symbol(self: @TState) -> felt252; fn token_uri(self: @TState, token_id: u256) -> felt252; + + // IERC721CamelOnly + fn balanceOf(self: @TState, account: ContractAddress) -> u256; + fn ownerOf(self: @TState, tokenId: u256) -> ContractAddress; + fn safeTransferFrom( + ref self: TState, + from: ContractAddress, + to: ContractAddress, + tokenId: u256, + data: Span + ); + fn transferFrom(ref self: TState, from: ContractAddress, to: ContractAddress, tokenId: u256); + fn setApprovalForAll(ref self: TState, operator: ContractAddress, approved: bool); + fn getApproved(self: @TState, tokenId: u256) -> ContractAddress; + fn isApprovedForAll(self: @TState, owner: ContractAddress, operator: ContractAddress) -> bool; + + // IERC721MetadataCamelOnly + fn tokenURI(self: @TState, tokenId: u256) -> felt252; } +// +// ERC721Receiver +// + #[starknet::interface] -trait IERC721MetadataCamelOnly { - fn tokenURI(self: @TState, tokenId: u256) -> felt252; +trait IERC721Receiver { + fn on_erc721_received( + self: @TState, + operator: ContractAddress, + from: ContractAddress, + token_id: u256, + data: Span + ) -> felt252; +} + +#[starknet::interface] +trait IERC721ReceiverCamel { + fn onERC721Received( + self: @TState, + operator: ContractAddress, + from: ContractAddress, + tokenId: u256, + data: Span + ) -> felt252; }