From 44992fca8f8c7a6a8b91f348675b1bed56c918d5 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Tue, 02 Nov 2021 11:37:58 +0000 Subject: [PATCH] feat: burn_from --- --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -459,6 +459,7 @@ fn transfer() -> Weight; fn approve() -> Weight; fn transfer_from() -> Weight; + fn burn_from() -> Weight; fn set_variable_metadata(bytes: u32) -> Weight; } @@ -504,6 +505,13 @@ token: TokenId, amount: u128, ) -> DispatchResultWithPostInfo; + fn burn_from( + &self, + sender: T::CrossAccountId, + from: T::CrossAccountId, + token: TokenId, + amount: u128, + ) -> DispatchResultWithPostInfo; fn set_variable_metadata( &self, --- a/pallets/fungible/src/common.rs +++ b/pallets/fungible/src/common.rs @@ -38,6 +38,10 @@ >::transfer_from() } + fn burn_from() -> Weight { + 0 + } + fn set_variable_metadata(_bytes: u32) -> Weight { // Error 0 @@ -156,6 +160,24 @@ ) } + fn burn_from( + &self, + sender: T::CrossAccountId, + from: T::CrossAccountId, + token: TokenId, + amount: u128, + ) -> DispatchResultWithPostInfo { + ensure!( + token == TokenId::default(), + >::FungibleItemsHaveNoId + ); + + with_weight( + >::burn_from(&self, &sender, &from, amount), + >::burn_from(), + ) + } + fn set_variable_metadata( &self, _sender: T::CrossAccountId, --- a/pallets/fungible/src/erc.rs +++ b/pallets/fungible/src/erc.rs @@ -96,6 +96,18 @@ } } +#[solidity_interface(name = "ERC20UniqueExtensions")] +impl FungibleHandle { + fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let from = T::CrossAccountId::from_eth(from); + let amount = amount.try_into().map_err(|_| "amount overflow")?; + + >::burn_from(self, &caller, &from, amount).map_err(dispatch_to_evm::)?; + Ok(true) + } +} + #[solidity_interface(name = "UniqueFungible", is(ERC20))] impl FungibleHandle {} --- a/pallets/fungible/src/lib.rs +++ b/pallets/fungible/src/lib.rs @@ -356,6 +356,38 @@ Ok(()) } + pub fn burn_from( + collection: &FungibleHandle, + spender: &T::CrossAccountId, + from: &T::CrossAccountId, + amount: u128, + ) -> DispatchResult { + if spender == from { + return Self::burn(collection, from, amount); + } + if collection.access == AccessMode::WhiteList { + // `from` checked in [`burn`] + collection.check_allowlist(spender)?; + } + + let allowance = >::get((collection.id, from.as_sub(), spender.as_sub())) + .checked_sub(amount); + if allowance.is_none() { + ensure!( + collection.ignores_allowance(spender)?, + >::TokenValueNotEnough + ); + } + + // ========= + + Self::burn(collection, from, amount)?; + if let Some(allowance) = allowance { + Self::set_allowance_unchecked(collection, from, spender, allowance); + } + Ok(()) + } + /// Delegated to `create_multiple_items` pub fn create_item( collection: &FungibleHandle, --- a/pallets/nft/src/common.rs +++ b/pallets/nft/src/common.rs @@ -45,4 +45,8 @@ fn set_variable_metadata(bytes: u32) -> nft_data_structs::Weight { dispatch_weight::() + max_weight_of!(set_variable_metadata(bytes)) } + + fn burn_from() -> Weight { + dispatch_weight::() + max_weight_of!(burn_from()) + } } --- a/pallets/nft/src/eth/sponsoring.rs +++ b/pallets/nft/src/eth/sponsoring.rs @@ -35,9 +35,10 @@ .map_err(|_| AnyError)? .ok_or(AnyError)?; match call { - UniqueNFTCall::ERC721UniqueExtensions( - ERC721UniqueExtensionsCall::TransferNft { token_id, .. }, - ) + UniqueNFTCall::ERC721UniqueExtensions(ERC721UniqueExtensionsCall::Transfer { + token_id, + .. + }) | UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => { let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?; let block_number = >::block_number() as T::BlockNumber; --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -623,14 +623,13 @@ /// * item_id: ID of NFT to burn. /// /// * from: owner of item - // #[weight = 0] - // #[transactional] - // pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> PostDispatchInfo { - // let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); + #[weight = >::burn_from()] + #[transactional] + pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo { + let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - // // dispatch_call::(collection_id, |d| d.burn_from(sender, from, item_id, value)) - // todo!() - // } + dispatch_call::(collection_id, |d| d.burn_from(sender, from, item_id, value)) + } /// Change ownership of the token. /// --- a/pallets/nonfungible/src/common.rs +++ b/pallets/nonfungible/src/common.rs @@ -39,6 +39,10 @@ >::transfer_from() } + fn burn_from() -> Weight { + 0 + } + fn set_variable_metadata(bytes: u32) -> Weight { >::set_variable_metadata(bytes) } @@ -163,6 +167,25 @@ } } + fn burn_from( + &self, + sender: T::CrossAccountId, + from: T::CrossAccountId, + token: TokenId, + amount: u128, + ) -> DispatchResultWithPostInfo { + ensure!(amount <= 1, >::NonfungibleItemsHaveNoAmount); + + if amount == 1 { + with_weight( + >::burn_from(&self, &sender, &from, token), + >::burn_from(), + ) + } else { + Ok(().into()) + } + } + fn set_variable_metadata( &self, sender: T::CrossAccountId, --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -264,8 +264,7 @@ #[solidity_interface(name = "ERC721UniqueExtensions")] impl NonfungibleHandle { - #[solidity(rename_selector = "transfer")] - fn transfer_nft( + fn transfer( &mut self, caller: caller, to: address, @@ -280,6 +279,21 @@ Ok(()) } + fn burn_from( + &mut self, + caller: caller, + from: address, + token_id: uint256, + _value: value, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let from = T::CrossAccountId::from_eth(from); + let token = token_id.try_into()?; + + >::burn_from(self, &caller, &from, token).map_err(dispatch_to_evm::)?; + Ok(()) + } + fn next_token_id(&self) -> Result { Ok(>::get(self.id) .checked_add(1) --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -499,6 +499,32 @@ Ok(()) } + pub fn burn_from( + collection: &NonfungibleHandle, + spender: &T::CrossAccountId, + from: &T::CrossAccountId, + token: TokenId, + ) -> DispatchResult { + if spender == from { + return Self::burn(collection, from, token); + } + if collection.access == AccessMode::WhiteList { + // `from` checked in [`burn`] + collection.check_allowlist(spender)?; + } + + if >::get((collection.id, token)).as_ref() != Some(spender) { + ensure!( + collection.ignores_allowance(spender)?, + >::TokenValueNotEnough + ); + } + + // ========= + + Self::burn(collection, &from, token) + } + pub fn set_variable_metadata( collection: &NonfungibleHandle, sender: &T::CrossAccountId, --- a/pallets/refungible/src/common.rs +++ b/pallets/refungible/src/common.rs @@ -59,6 +59,10 @@ ) } + fn burn_from() -> Weight { + 0 + } + fn set_variable_metadata(bytes: u32) -> Weight { >::set_variable_metadata(bytes) } @@ -161,7 +165,20 @@ ) -> DispatchResultWithPostInfo { with_weight( >::transfer_from(&self, &sender, &from, &to, token, amount), - >::approve(), + >::transfer_from(), + ) + } + + fn burn_from( + &self, + sender: T::CrossAccountId, + from: T::CrossAccountId, + token: TokenId, + amount: u128, + ) -> DispatchResultWithPostInfo { + with_weight( + >::burn_from(&self, &sender, &from, token, amount), + >::burn_from(), ) } --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -537,6 +537,39 @@ Ok(()) } + pub fn burn_from( + collection: &RefungibleHandle, + spender: &T::CrossAccountId, + from: &T::CrossAccountId, + token: TokenId, + amount: u128, + ) -> DispatchResult { + if spender == from { + return Self::burn(collection, from, token, amount); + } + if collection.access == AccessMode::WhiteList { + // `from` checked in [`burn`] + collection.check_allowlist(spender)?; + } + + let allowance = >::get((collection.id, token, from.as_sub(), &spender)) + .checked_sub(amount); + if allowance.is_none() { + ensure!( + collection.ignores_allowance(spender)?, + >::TokenValueNotEnough + ); + } + + // ========= + + Self::burn(collection, from, token, amount)?; + if let Some(allowance) = allowance { + Self::set_allowance_unchecked(collection, from, spender, token, allowance); + } + Ok(()) + } + pub fn set_variable_metadata( collection: &RefungibleHandle, sender: &T::CrossAccountId, -- gitstuff