From ddfbd4531fc919b7be5e49b8b4db7d7ff90b4dbd Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Sun, 29 Sep 2024 04:50:27 +0100 Subject: [PATCH 1/6] add burn function --- .../src/token/erc721_bridgeable.cairo | 87 +++++++++++-------- .../starknet/src/token/interfaces.cairo | 2 + 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo index 9ec9419c..579becb2 100644 --- a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo +++ b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo @@ -21,7 +21,7 @@ mod erc721_bridgeable { impl ERC721Impl = ERC721Component::ERC721Impl; #[abi(embed_v0)] impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl; - + impl ERC721InternalImpl = ERC721Component::InternalImpl; // SRC5 @@ -29,7 +29,8 @@ mod erc721_bridgeable { impl SRC5Impl = SRC5Component::SRC5Impl; #[abi(embed_v0)] - impl OwnableTwoStepMixinImpl = OwnableComponent::OwnableTwoStepMixinImpl; + impl OwnableTwoStepMixinImpl = + OwnableComponent::OwnableTwoStepMixinImpl; impl OwnableInternalImpl = OwnableComponent::InternalImpl; @@ -79,21 +80,27 @@ mod erc721_bridgeable { impl ERC721BridgeableImpl of IERC721Bridgeable { fn mint_from_bridge(ref self: ContractState, to: ContractAddress, token_id: u256) { assert( - starknet::get_caller_address() == self.bridge.read(), - 'ERC721: only bridge can mint' + starknet::get_caller_address() == self.bridge.read(), 'ERC721: only bridge can mint' ); self.erc721._mint(to, token_id); } - fn mint_from_bridge_uri(ref self: ContractState, to: ContractAddress, token_id: u256, token_uri: ByteArray) { + fn mint_from_bridge_uri( + ref self: ContractState, to: ContractAddress, token_id: u256, token_uri: ByteArray + ) { IERC721Bridgeable::mint_from_bridge(ref self, to, token_id); self.token_uris.write(token_id, token_uri); } + fn burn(ref self: ContractState, token_id: u256) { + self.erc721._burn(token_id); + } } #[abi(embed_v0)] - impl ERC721BridgeableMetadataImpl of ERC721Component::interface::IERC721Metadata { + impl ERC721BridgeableMetadataImpl of ERC721Component::interface::IERC721Metadata< + ContractState + > { fn name(self: @ContractState) -> ByteArray { self.erc721.name() } @@ -113,7 +120,9 @@ mod erc721_bridgeable { } #[abi(embed_v0)] - impl ERC721BridgeableMetadataCamelOnlyImpl of ERC721Component::interface::IERC721MetadataCamelOnly { + impl ERC721BridgeableMetadataCamelOnlyImpl of ERC721Component::interface::IERC721MetadataCamelOnly< + ContractState + > { fn tokenURI(self: @ContractState, tokenId: u256) -> ByteArray { self.token_uri(tokenId) } @@ -141,15 +150,17 @@ mod erc721_bridgeable { fn mint_range(ref self: ContractState, to: ContractAddress, start: u256, end: u256) { let mut token_id = start; loop { - if token_id == end { - break (); - } + if token_id == end { + break (); + } self.mint(to, token_id); token_id += 1_u256; } } - fn mint_uri(ref self: ContractState, to: ContractAddress, token_id: u256, token_uri: ByteArray) { + fn mint_uri( + ref self: ContractState, to: ContractAddress, token_id: u256, token_uri: ByteArray + ) { self.mint(to, token_id); self.token_uris.write(token_id, token_uri); } @@ -183,9 +194,8 @@ mod tests { }; use starklane::token::interfaces::{ - IERC721BridgeableDispatcher, IERC721BridgeableDispatcherTrait, - IERC721Dispatcher, IERC721DispatcherTrait, - IERC721MintableDispatcher, IERC721MintableDispatcherTrait, + IERC721BridgeableDispatcher, IERC721BridgeableDispatcherTrait, IERC721Dispatcher, + IERC721DispatcherTrait, IERC721MintableDispatcher, IERC721MintableDispatcherTrait, IERC721UriDispatcher, IERC721UriDispatcherTrait, }; use starklane::token::collection_manager; @@ -241,7 +251,8 @@ mod tests { "DUO", "https://my.base.uri", bridge_addr_mock(), - collection_owner_addr_mock()) + collection_owner_addr_mock() + ) } /// Should have correct constructor valules. @@ -265,11 +276,12 @@ mod tests { let TOKEN_ID = 244; let contract_address = deploy_everai_collection(); - let erc721 = IERC721Dispatcher { contract_address }; - + let erc721 = IERC721Dispatcher { contract_address }; + let new_uri = "https:..."; start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721MintableDispatcher { contract_address }.mint_uri(NEW_DUO_OWNER, TOKEN_ID, new_uri.clone()); + IERC721MintableDispatcher { contract_address } + .mint_uri(NEW_DUO_OWNER, TOKEN_ID, new_uri.clone()); stop_prank(CheatTarget::One(contract_address)); let fetched_uri = erc721.token_uri(TOKEN_ID); @@ -280,7 +292,7 @@ mod tests { #[test] fn mint_from_bridge() { let BRIDGE = bridge_addr_mock(); - + let NEW_DUO_OWNER = starknet::contract_address_const::<128>(); let contract_address = deploy_everai_collection(); @@ -298,7 +310,7 @@ mod tests { /// Should not mint token if not bridge. #[test] - #[should_panic(expected: ('ERC721: only bridge can mint', ))] + #[should_panic(expected: ('ERC721: only bridge can mint',))] fn should_panic_mint_from_bridge_fail() { let NEW_DUO_OWNER = starknet::contract_address_const::<128>(); @@ -348,7 +360,9 @@ mod tests { erc721.mint_uri(NEW_DUO_OWNER, TOKEN_ID, new_uri.clone()); stop_prank(CheatTarget::One(contract_address)); - let fetched_uri = collection_manager::token_uri_from_contract_call(contract_address, TOKEN_ID) + let fetched_uri = collection_manager::token_uri_from_contract_call( + contract_address, TOKEN_ID + ) .expect('token mint failed'); assert_eq!(fetched_uri, new_uri, "bad uri"); } @@ -390,7 +404,7 @@ mod tests { stop_prank(CheatTarget::One(contract_address)); assert_eq!(ownable.owner(), COLLECTION_OWNER, "bad owner"); assert_eq!(ownable.pending_owner(), ALICE, "bad pending owner"); - + start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); ownable.transfer_ownership(BOB); stop_prank(CheatTarget::One(contract_address)); @@ -428,7 +442,7 @@ mod tests { let new_uri = "https://this.is.a.test.com"; let contract_address = deploy_everai_collection(); - let contract = IERC721UriDispatcher { contract_address}; + let contract = IERC721UriDispatcher { contract_address }; assert_eq!(contract.base_uri(), "https://my.base.uri"); start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); contract.set_base_uri(new_uri.clone()); @@ -448,7 +462,7 @@ mod tests { assert_eq!(ownable.owner(), COLLECTION_OWNER, "bad owner"); start_prank(CheatTarget::One(contract_address), ALICE); - IERC721UriDispatcher { contract_address}.set_base_uri("https://this.is.a.test.com"); + IERC721UriDispatcher { contract_address }.set_base_uri("https://this.is.a.test.com"); stop_prank(CheatTarget::One(contract_address)); } @@ -461,14 +475,14 @@ mod tests { let token_id = 42_u256; start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721MintableDispatcher { contract_address}.mint(ALICE, token_id); + IERC721MintableDispatcher { contract_address }.mint(ALICE, token_id); stop_prank(CheatTarget::One(contract_address)); - assert!(IERC721Dispatcher {contract_address}.token_uri(token_id) != new_uri.clone()); + assert!(IERC721Dispatcher { contract_address }.token_uri(token_id) != new_uri.clone()); start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721UriDispatcher { contract_address}.set_token_uri(token_id, new_uri.clone()); + IERC721UriDispatcher { contract_address }.set_token_uri(token_id, new_uri.clone()); stop_prank(CheatTarget::One(contract_address)); - assert_eq!(IERC721Dispatcher {contract_address}.token_uri(token_id), new_uri); + assert_eq!(IERC721Dispatcher { contract_address }.token_uri(token_id), new_uri); } #[test] @@ -482,14 +496,14 @@ mod tests { let invalid_token_id = 68_u256; start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721MintableDispatcher { contract_address}.mint(ALICE, token_id); + IERC721MintableDispatcher { contract_address }.mint(ALICE, token_id); stop_prank(CheatTarget::One(contract_address)); - assert!(IERC721Dispatcher {contract_address}.token_uri(token_id) != new_uri.clone()); + assert!(IERC721Dispatcher { contract_address }.token_uri(token_id) != new_uri.clone()); start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721UriDispatcher { contract_address}.set_token_uri(invalid_token_id, new_uri.clone()); + IERC721UriDispatcher { contract_address }.set_token_uri(invalid_token_id, new_uri.clone()); stop_prank(CheatTarget::One(contract_address)); - assert_eq!(IERC721Dispatcher {contract_address}.token_uri(token_id), new_uri); + assert_eq!(IERC721Dispatcher { contract_address }.token_uri(token_id), new_uri); } #[test] @@ -502,14 +516,13 @@ mod tests { let token_id = 42_u256; start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721MintableDispatcher { contract_address}.mint(ALICE, token_id); + IERC721MintableDispatcher { contract_address }.mint(ALICE, token_id); stop_prank(CheatTarget::One(contract_address)); - assert!(IERC721Dispatcher {contract_address}.token_uri(token_id) != new_uri.clone()); + assert!(IERC721Dispatcher { contract_address }.token_uri(token_id) != new_uri.clone()); start_prank(CheatTarget::One(contract_address), ALICE); - IERC721UriDispatcher { contract_address}.set_token_uri(token_id, new_uri.clone()); + IERC721UriDispatcher { contract_address }.set_token_uri(token_id, new_uri.clone()); stop_prank(CheatTarget::One(contract_address)); - assert_eq!(IERC721Dispatcher {contract_address}.token_uri(token_id), new_uri); + assert_eq!(IERC721Dispatcher { contract_address }.token_uri(token_id), new_uri); } - } diff --git a/apps/blockchain/starknet/src/token/interfaces.cairo b/apps/blockchain/starknet/src/token/interfaces.cairo index 5d27fcf2..811a736c 100644 --- a/apps/blockchain/starknet/src/token/interfaces.cairo +++ b/apps/blockchain/starknet/src/token/interfaces.cairo @@ -33,4 +33,6 @@ trait IERC721Bridgeable { fn mint_from_bridge(ref self: T, to: ContractAddress, token_id: u256); fn mint_from_bridge_uri(ref self: T, to: ContractAddress, token_id: u256, token_uri: ByteArray); + + fn burn(ref self: T, token_id: u256); } From 4b860908d088a08330f65bfa08e43ca281a56217 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Sun, 29 Sep 2024 16:59:47 +0100 Subject: [PATCH 2/6] remove formatting --- .../src/token/erc721_bridgeable.cairo | 94 +++++++++---------- .../starknet/src/token/interfaces.cairo | 3 +- 2 files changed, 45 insertions(+), 52 deletions(-) diff --git a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo index 579becb2..64ae4b7e 100644 --- a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo +++ b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo @@ -21,7 +21,7 @@ mod erc721_bridgeable { impl ERC721Impl = ERC721Component::ERC721Impl; #[abi(embed_v0)] impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl; - + impl ERC721InternalImpl = ERC721Component::InternalImpl; // SRC5 @@ -29,8 +29,7 @@ mod erc721_bridgeable { impl SRC5Impl = SRC5Component::SRC5Impl; #[abi(embed_v0)] - impl OwnableTwoStepMixinImpl = - OwnableComponent::OwnableTwoStepMixinImpl; + impl OwnableTwoStepMixinImpl = OwnableComponent::OwnableTwoStepMixinImpl; impl OwnableInternalImpl = OwnableComponent::InternalImpl; @@ -80,27 +79,26 @@ mod erc721_bridgeable { impl ERC721BridgeableImpl of IERC721Bridgeable { fn mint_from_bridge(ref self: ContractState, to: ContractAddress, token_id: u256) { assert( - starknet::get_caller_address() == self.bridge.read(), 'ERC721: only bridge can mint' + starknet::get_caller_address() == self.bridge.read(), + 'ERC721: only bridge can mint' ); self.erc721._mint(to, token_id); } - fn mint_from_bridge_uri( - ref self: ContractState, to: ContractAddress, token_id: u256, token_uri: ByteArray - ) { - IERC721Bridgeable::mint_from_bridge(ref self, to, token_id); - self.token_uris.write(token_id, token_uri); - } fn burn(ref self: ContractState, token_id: u256) { self.erc721._burn(token_id); } + + + fn mint_from_bridge_uri(ref self: ContractState, to: ContractAddress, token_id: u256, token_uri: ByteArray) { + IERC721Bridgeable::mint_from_bridge(ref self, to, token_id); + self.token_uris.write(token_id, token_uri); + } } #[abi(embed_v0)] - impl ERC721BridgeableMetadataImpl of ERC721Component::interface::IERC721Metadata< - ContractState - > { + impl ERC721BridgeableMetadataImpl of ERC721Component::interface::IERC721Metadata { fn name(self: @ContractState) -> ByteArray { self.erc721.name() } @@ -120,9 +118,7 @@ mod erc721_bridgeable { } #[abi(embed_v0)] - impl ERC721BridgeableMetadataCamelOnlyImpl of ERC721Component::interface::IERC721MetadataCamelOnly< - ContractState - > { + impl ERC721BridgeableMetadataCamelOnlyImpl of ERC721Component::interface::IERC721MetadataCamelOnly { fn tokenURI(self: @ContractState, tokenId: u256) -> ByteArray { self.token_uri(tokenId) } @@ -150,17 +146,15 @@ mod erc721_bridgeable { fn mint_range(ref self: ContractState, to: ContractAddress, start: u256, end: u256) { let mut token_id = start; loop { - if token_id == end { - break (); - } + if token_id == end { + break (); + } self.mint(to, token_id); token_id += 1_u256; } } - fn mint_uri( - ref self: ContractState, to: ContractAddress, token_id: u256, token_uri: ByteArray - ) { + fn mint_uri(ref self: ContractState, to: ContractAddress, token_id: u256, token_uri: ByteArray) { self.mint(to, token_id); self.token_uris.write(token_id, token_uri); } @@ -194,8 +188,9 @@ mod tests { }; use starklane::token::interfaces::{ - IERC721BridgeableDispatcher, IERC721BridgeableDispatcherTrait, IERC721Dispatcher, - IERC721DispatcherTrait, IERC721MintableDispatcher, IERC721MintableDispatcherTrait, + IERC721BridgeableDispatcher, IERC721BridgeableDispatcherTrait, + IERC721Dispatcher, IERC721DispatcherTrait, + IERC721MintableDispatcher, IERC721MintableDispatcherTrait, IERC721UriDispatcher, IERC721UriDispatcherTrait, }; use starklane::token::collection_manager; @@ -251,8 +246,7 @@ mod tests { "DUO", "https://my.base.uri", bridge_addr_mock(), - collection_owner_addr_mock() - ) + collection_owner_addr_mock()) } /// Should have correct constructor valules. @@ -276,12 +270,11 @@ mod tests { let TOKEN_ID = 244; let contract_address = deploy_everai_collection(); - let erc721 = IERC721Dispatcher { contract_address }; - + let erc721 = IERC721Dispatcher { contract_address }; + let new_uri = "https:..."; start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721MintableDispatcher { contract_address } - .mint_uri(NEW_DUO_OWNER, TOKEN_ID, new_uri.clone()); + IERC721MintableDispatcher { contract_address }.mint_uri(NEW_DUO_OWNER, TOKEN_ID, new_uri.clone()); stop_prank(CheatTarget::One(contract_address)); let fetched_uri = erc721.token_uri(TOKEN_ID); @@ -292,7 +285,7 @@ mod tests { #[test] fn mint_from_bridge() { let BRIDGE = bridge_addr_mock(); - + let NEW_DUO_OWNER = starknet::contract_address_const::<128>(); let contract_address = deploy_everai_collection(); @@ -310,7 +303,7 @@ mod tests { /// Should not mint token if not bridge. #[test] - #[should_panic(expected: ('ERC721: only bridge can mint',))] + #[should_panic(expected: ('ERC721: only bridge can mint', ))] fn should_panic_mint_from_bridge_fail() { let NEW_DUO_OWNER = starknet::contract_address_const::<128>(); @@ -360,9 +353,7 @@ mod tests { erc721.mint_uri(NEW_DUO_OWNER, TOKEN_ID, new_uri.clone()); stop_prank(CheatTarget::One(contract_address)); - let fetched_uri = collection_manager::token_uri_from_contract_call( - contract_address, TOKEN_ID - ) + let fetched_uri = collection_manager::token_uri_from_contract_call(contract_address, TOKEN_ID) .expect('token mint failed'); assert_eq!(fetched_uri, new_uri, "bad uri"); } @@ -404,7 +395,7 @@ mod tests { stop_prank(CheatTarget::One(contract_address)); assert_eq!(ownable.owner(), COLLECTION_OWNER, "bad owner"); assert_eq!(ownable.pending_owner(), ALICE, "bad pending owner"); - + start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); ownable.transfer_ownership(BOB); stop_prank(CheatTarget::One(contract_address)); @@ -442,7 +433,7 @@ mod tests { let new_uri = "https://this.is.a.test.com"; let contract_address = deploy_everai_collection(); - let contract = IERC721UriDispatcher { contract_address }; + let contract = IERC721UriDispatcher { contract_address}; assert_eq!(contract.base_uri(), "https://my.base.uri"); start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); contract.set_base_uri(new_uri.clone()); @@ -462,7 +453,7 @@ mod tests { assert_eq!(ownable.owner(), COLLECTION_OWNER, "bad owner"); start_prank(CheatTarget::One(contract_address), ALICE); - IERC721UriDispatcher { contract_address }.set_base_uri("https://this.is.a.test.com"); + IERC721UriDispatcher { contract_address}.set_base_uri("https://this.is.a.test.com"); stop_prank(CheatTarget::One(contract_address)); } @@ -475,14 +466,14 @@ mod tests { let token_id = 42_u256; start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721MintableDispatcher { contract_address }.mint(ALICE, token_id); + IERC721MintableDispatcher { contract_address}.mint(ALICE, token_id); stop_prank(CheatTarget::One(contract_address)); - assert!(IERC721Dispatcher { contract_address }.token_uri(token_id) != new_uri.clone()); + assert!(IERC721Dispatcher {contract_address}.token_uri(token_id) != new_uri.clone()); start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721UriDispatcher { contract_address }.set_token_uri(token_id, new_uri.clone()); + IERC721UriDispatcher { contract_address}.set_token_uri(token_id, new_uri.clone()); stop_prank(CheatTarget::One(contract_address)); - assert_eq!(IERC721Dispatcher { contract_address }.token_uri(token_id), new_uri); + assert_eq!(IERC721Dispatcher {contract_address}.token_uri(token_id), new_uri); } #[test] @@ -496,14 +487,14 @@ mod tests { let invalid_token_id = 68_u256; start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721MintableDispatcher { contract_address }.mint(ALICE, token_id); + IERC721MintableDispatcher { contract_address}.mint(ALICE, token_id); stop_prank(CheatTarget::One(contract_address)); - assert!(IERC721Dispatcher { contract_address }.token_uri(token_id) != new_uri.clone()); + assert!(IERC721Dispatcher {contract_address}.token_uri(token_id) != new_uri.clone()); start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721UriDispatcher { contract_address }.set_token_uri(invalid_token_id, new_uri.clone()); + IERC721UriDispatcher { contract_address}.set_token_uri(invalid_token_id, new_uri.clone()); stop_prank(CheatTarget::One(contract_address)); - assert_eq!(IERC721Dispatcher { contract_address }.token_uri(token_id), new_uri); + assert_eq!(IERC721Dispatcher {contract_address}.token_uri(token_id), new_uri); } #[test] @@ -516,13 +507,14 @@ mod tests { let token_id = 42_u256; start_prank(CheatTarget::One(contract_address), COLLECTION_OWNER); - IERC721MintableDispatcher { contract_address }.mint(ALICE, token_id); + IERC721MintableDispatcher { contract_address}.mint(ALICE, token_id); stop_prank(CheatTarget::One(contract_address)); - assert!(IERC721Dispatcher { contract_address }.token_uri(token_id) != new_uri.clone()); + assert!(IERC721Dispatcher {contract_address}.token_uri(token_id) != new_uri.clone()); start_prank(CheatTarget::One(contract_address), ALICE); - IERC721UriDispatcher { contract_address }.set_token_uri(token_id, new_uri.clone()); + IERC721UriDispatcher { contract_address}.set_token_uri(token_id, new_uri.clone()); stop_prank(CheatTarget::One(contract_address)); - assert_eq!(IERC721Dispatcher { contract_address }.token_uri(token_id), new_uri); + assert_eq!(IERC721Dispatcher {contract_address}.token_uri(token_id), new_uri); } -} + +} \ No newline at end of file diff --git a/apps/blockchain/starknet/src/token/interfaces.cairo b/apps/blockchain/starknet/src/token/interfaces.cairo index 811a736c..37f672a4 100644 --- a/apps/blockchain/starknet/src/token/interfaces.cairo +++ b/apps/blockchain/starknet/src/token/interfaces.cairo @@ -30,9 +30,10 @@ trait IERC721Mintable { /// ERC721 that can be manipulated by the bridge. #[starknet::interface] trait IERC721Bridgeable { + fn burn(ref self: T, token_id: u256); + fn mint_from_bridge(ref self: T, to: ContractAddress, token_id: u256); fn mint_from_bridge_uri(ref self: T, to: ContractAddress, token_id: u256, token_uri: ByteArray); - fn burn(ref self: T, token_id: u256); } From ca16fc9b4ceacd5bf8da9a71b3f37673fcb5b170 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Wed, 2 Oct 2024 10:32:54 +0100 Subject: [PATCH 3/6] unit test for burn function --- .../src/token/erc721_bridgeable.cairo | 33 +++++++++++++++++++ .../starknet/src/token/interfaces.cairo | 5 ++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo index 64ae4b7e..cd507b23 100644 --- a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo +++ b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo @@ -301,6 +301,39 @@ mod tests { assert_eq!(erc721.token_uri(0), "myuri", "bad uri"); } + /// Should burn token from bridge call. + #[test] + fn burn_from_bridge() { + let BRIDGE = bridge_addr_mock(); + + let DUO_OWNER = starknet::contract_address_const::<128>(); + + let contract_address = deploy_everai_collection(); + + let erc721b = IERC721BridgeableDispatcher { contract_address }; + + // Mint a token first to be able to burn it later + start_prank(CheatTarget::One(contract_address), BRIDGE); + erc721b.mint_from_bridge(DUO_OWNER, 42_u256); + stop_prank(CheatTarget::One(contract_address)); + + // Check that the owner is set correctly after minting + let erc721 = IERC721Dispatcher { contract_address }; + assert!(erc721.owner_of(42_u256) == DUO_OWNER, "bad owner after mint"); + + // Burn the token + start_prank(CheatTarget::One(contract_address), BRIDGE); + erc721b.burn(42_u256); + stop_prank(CheatTarget::One(contract_address)); + + // balance_of + start_prank(CheatTarget::One(contract_address), BRIDGE); + let balance = erc721.balance_of(BRIDGE); + assert(balance == 0, 'token was not burn'); + stop_prank(CheatTarget::One(contract_address)); + + } + /// Should not mint token if not bridge. #[test] #[should_panic(expected: ('ERC721: only bridge can mint', ))] diff --git a/apps/blockchain/starknet/src/token/interfaces.cairo b/apps/blockchain/starknet/src/token/interfaces.cairo index 37f672a4..9d6163cb 100644 --- a/apps/blockchain/starknet/src/token/interfaces.cairo +++ b/apps/blockchain/starknet/src/token/interfaces.cairo @@ -7,7 +7,7 @@ trait IERC721 { fn owner_of(self: @T, token_id: u256) -> ContractAddress; fn token_uri(self: @T, token_id: u256) -> ByteArray; fn is_approved_for_all(self: @T, owner: ContractAddress, operator: ContractAddress) -> bool; - + fn balance_of(self: @T, owner: ContractAddress) -> u256; fn set_approval_for_all(ref self: T, operator: ContractAddress, approved: bool); fn transfer_from(ref self: T, from: ContractAddress, to: ContractAddress, token_id: u256); fn approve(ref self: T, to: ContractAddress, token_id: u256); @@ -31,9 +31,8 @@ trait IERC721Mintable { #[starknet::interface] trait IERC721Bridgeable { fn burn(ref self: T, token_id: u256); - + fn mint_from_bridge(ref self: T, to: ContractAddress, token_id: u256); fn mint_from_bridge_uri(ref self: T, to: ContractAddress, token_id: u256, token_uri: ByteArray); - } From 021111bf6375b4a6b65b060662fba7d232ce1125 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Fri, 4 Oct 2024 08:27:53 +0100 Subject: [PATCH 4/6] only token owner can burn a token --- .../starknet/src/token/erc721_bridgeable.cairo | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo index cd507b23..4813b850 100644 --- a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo +++ b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo @@ -87,6 +87,8 @@ mod erc721_bridgeable { } fn burn(ref self: ContractState, token_id: u256) { + let token_owner = self.erc721.owner_of(token_id); + assert(token_owner == starknet::get_caller_address(), 'ERC721: only owner can burn'); self.erc721._burn(token_id); } @@ -301,7 +303,8 @@ mod tests { assert_eq!(erc721.token_uri(0), "myuri", "bad uri"); } - /// Should burn token from bridge call. + + /// Should burn token from bridge call. #[test] fn burn_from_bridge() { let BRIDGE = bridge_addr_mock(); @@ -322,15 +325,15 @@ mod tests { assert!(erc721.owner_of(42_u256) == DUO_OWNER, "bad owner after mint"); // Burn the token - start_prank(CheatTarget::One(contract_address), BRIDGE); + start_prank(CheatTarget::One(contract_address), DUO_OWNER); erc721b.burn(42_u256); stop_prank(CheatTarget::One(contract_address)); // balance_of - start_prank(CheatTarget::One(contract_address), BRIDGE); - let balance = erc721.balance_of(BRIDGE); - assert(balance == 0, 'token was not burn'); - stop_prank(CheatTarget::One(contract_address)); + + let balance = erc721.balance_of(DUO_OWNER); + assert(balance == 0, 'token was not burn'); + } From f1fac121f2352ce7faeeb02586796bd13dd2155e Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Fri, 4 Oct 2024 09:05:09 +0100 Subject: [PATCH 5/6] should panic if wrong owner try to burn token --- .../src/token/erc721_bridgeable.cairo | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo index 4813b850..a2dbc578 100644 --- a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo +++ b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo @@ -337,6 +337,34 @@ mod tests { } + /// Should panic, only owner can burn + #[test] + #[should_panic(expected: ('ERC721: only owner can burn', ))] + fn should_panic_burn_from_bridge() { + let BRIDGE = bridge_addr_mock(); + + let DUO_OWNER = starknet::contract_address_const::<128>(); + + let contract_address = deploy_everai_collection(); + + let erc721b = IERC721BridgeableDispatcher { contract_address }; + + // Mint a token first to be able to burn it later + start_prank(CheatTarget::One(contract_address), BRIDGE); + erc721b.mint_from_bridge(DUO_OWNER, 42_u256); + stop_prank(CheatTarget::One(contract_address)); + + // Check that the owner is set correctly after minting + let erc721 = IERC721Dispatcher { contract_address }; + assert!(erc721.owner_of(42_u256) == DUO_OWNER, "bad owner after mint"); + + // Burn the token by wrong owner + start_prank(CheatTarget::One(contract_address), BRIDGE); + erc721b.burn(42_u256); + + + } + /// Should not mint token if not bridge. #[test] #[should_panic(expected: ('ERC721: only bridge can mint', ))] From ddbc2330edf26f4070b8f85f7933f4f58ea2a6dc Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Fri, 4 Oct 2024 16:29:28 +0100 Subject: [PATCH 6/6] rename test function name --- apps/blockchain/starknet/src/token/erc721_bridgeable.cairo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo index a2dbc578..b518b611 100644 --- a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo +++ b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo @@ -306,7 +306,7 @@ mod tests { /// Should burn token from bridge call. #[test] - fn burn_from_bridge() { + fn test_burn_token() { let BRIDGE = bridge_addr_mock(); let DUO_OWNER = starknet::contract_address_const::<128>(); @@ -340,7 +340,7 @@ mod tests { /// Should panic, only owner can burn #[test] #[should_panic(expected: ('ERC721: only owner can burn', ))] - fn should_panic_burn_from_bridge() { + fn should_panic_test_burn_token() { let BRIDGE = bridge_addr_mock(); let DUO_OWNER = starknet::contract_address_const::<128>();