From b78a45d53d3384f112ccefb750e6d1097a03daf6 Mon Sep 17 00:00:00 2001 From: Mubarak Muhammad Aminu Date: Mon, 7 Oct 2024 23:15:49 +0100 Subject: [PATCH] add burn function (#243) * add burn function * remove formatting * unit test for burn function * only token owner can burn a token * should panic if wrong owner try to burn token * rename test function name --- .../src/token/erc721_bridgeable.cairo | 71 ++++++++++++++++++- .../starknet/src/token/interfaces.cairo | 4 +- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo index 9ec9419c..b518b611 100644 --- a/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo +++ b/apps/blockchain/starknet/src/token/erc721_bridgeable.cairo @@ -86,6 +86,13 @@ mod erc721_bridgeable { self.erc721._mint(to, token_id); } + 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); + } + + 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); @@ -296,6 +303,68 @@ mod tests { assert_eq!(erc721.token_uri(0), "myuri", "bad uri"); } + + /// Should burn token from bridge call. + #[test] + fn test_burn_token() { + 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), DUO_OWNER); + erc721b.burn(42_u256); + stop_prank(CheatTarget::One(contract_address)); + + // balance_of + + let balance = erc721.balance_of(DUO_OWNER); + assert(balance == 0, 'token was not burn'); + + + } + + /// Should panic, only owner can burn + #[test] + #[should_panic(expected: ('ERC721: only owner can burn', ))] + fn should_panic_test_burn_token() { + 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', ))] @@ -512,4 +581,4 @@ mod tests { 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 5d27fcf2..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); @@ -30,6 +30,8 @@ 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);