difftreelog
feat burn_from
in: master
12 files changed
pallets/common/src/lib.rsdiffbeforeafterboth--- 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,
pallets/fungible/src/common.rsdiffbeforeafterboth1use core::marker::PhantomData;23use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};4use nft_data_structs::TokenId;5use pallet_common::{6 CommonCollectionOperations, CommonWeightInfo, account::CrossAccountId, with_weight,7};8use sp_runtime::ArithmeticError;9use sp_std::{vec::Vec, vec};1011use crate::{12 Allowance, Balance, Config, Error, FungibleHandle, Pallet, SelfWeightOf, weights::WeightInfo,13};1415pub struct CommonWeights<T: Config>(PhantomData<T>);16impl<T: Config> CommonWeightInfo for CommonWeights<T> {17 fn create_item() -> Weight {18 <SelfWeightOf<T>>::create_item()19 }2021 fn create_multiple_items(_amount: u32) -> Weight {22 Self::create_item()23 }2425 fn burn_item() -> Weight {26 <SelfWeightOf<T>>::burn_item()27 }2829 fn transfer() -> Weight {30 <SelfWeightOf<T>>::transfer()31 }3233 fn approve() -> Weight {34 <SelfWeightOf<T>>::approve()35 }3637 fn transfer_from() -> Weight {38 <SelfWeightOf<T>>::transfer_from()39 }4041 fn set_variable_metadata(_bytes: u32) -> Weight {42 // Error43 044 }45}4647impl<T: Config> CommonCollectionOperations<T> for FungibleHandle<T> {48 fn create_item(49 &self,50 sender: T::CrossAccountId,51 to: T::CrossAccountId,52 data: nft_data_structs::CreateItemData,53 ) -> DispatchResultWithPostInfo {54 match data {55 nft_data_structs::CreateItemData::Fungible(data) => with_weight(56 <Pallet<T>>::create_item(self, &sender, (to, data.value)),57 <CommonWeights<T>>::create_item(),58 ),59 _ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),60 }61 }6263 fn create_multiple_items(64 &self,65 sender: T::CrossAccountId,66 to: T::CrossAccountId,67 data: Vec<nft_data_structs::CreateItemData>,68 ) -> DispatchResultWithPostInfo {69 let mut sum: u128 = 0;70 for data in data {71 match data {72 nft_data_structs::CreateItemData::Fungible(data) => {73 sum = sum74 .checked_add(data.value)75 .ok_or(ArithmeticError::Overflow)?;76 }77 _ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),78 }79 }8081 with_weight(82 <Pallet<T>>::create_item(self, &sender, (to, sum)),83 <CommonWeights<T>>::create_item(),84 )85 }8687 fn burn_item(88 &self,89 sender: T::CrossAccountId,90 token: TokenId,91 amount: u128,92 ) -> DispatchResultWithPostInfo {93 ensure!(94 token == TokenId::default(),95 <Error<T>>::FungibleItemsHaveNoId96 );9798 with_weight(99 <Pallet<T>>::burn(self, &sender, amount),100 <CommonWeights<T>>::burn_item(),101 )102 }103104 fn transfer(105 &self,106 from: T::CrossAccountId,107 to: T::CrossAccountId,108 token: TokenId,109 amount: u128,110 ) -> DispatchResultWithPostInfo {111 ensure!(112 token == TokenId::default(),113 <Error<T>>::FungibleItemsHaveNoId114 );115116 with_weight(117 <Pallet<T>>::transfer(&self, &from, &to, amount),118 <CommonWeights<T>>::transfer(),119 )120 }121122 fn approve(123 &self,124 sender: T::CrossAccountId,125 spender: T::CrossAccountId,126 token: TokenId,127 amount: u128,128 ) -> DispatchResultWithPostInfo {129 ensure!(130 token == TokenId::default(),131 <Error<T>>::FungibleItemsHaveNoId132 );133134 with_weight(135 <Pallet<T>>::set_allowance(&self, &sender, &spender, amount),136 <CommonWeights<T>>::approve(),137 )138 }139140 fn transfer_from(141 &self,142 sender: T::CrossAccountId,143 from: T::CrossAccountId,144 to: T::CrossAccountId,145 token: TokenId,146 amount: u128,147 ) -> DispatchResultWithPostInfo {148 ensure!(149 token == TokenId::default(),150 <Error<T>>::FungibleItemsHaveNoId151 );152153 with_weight(154 <Pallet<T>>::transfer_from(&self, &sender, &from, &to, amount),155 <CommonWeights<T>>::transfer_from(),156 )157 }158159 fn set_variable_metadata(160 &self,161 _sender: T::CrossAccountId,162 _token: TokenId,163 _data: Vec<u8>,164 ) -> DispatchResultWithPostInfo {165 fail!(<Error<T>>::FungibleItemsHaveData)166 }167168 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {169 if <Balance<T>>::get((self.id, account.as_sub())) != 0 {170 vec![TokenId::default()]171 } else {172 vec![]173 }174 }175176 fn token_exists(&self, token: TokenId) -> bool {177 token == TokenId::default()178 }179180 fn last_token_id(&self) -> TokenId {181 TokenId::default()182 }183184 fn token_owner(&self, _token: TokenId) -> T::CrossAccountId {185 T::CrossAccountId::default()186 }187 fn const_metadata(&self, _token: TokenId) -> Vec<u8> {188 Vec::new()189 }190 fn variable_metadata(&self, _token: TokenId) -> Vec<u8> {191 Vec::new()192 }193194 fn collection_tokens(&self) -> u32 {195 1196 }197198 fn account_balance(&self, account: T::CrossAccountId) -> u32 {199 if <Balance<T>>::get((self.id, account.as_sub())) != 0 {200 1201 } else {202 0203 }204 }205206 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {207 if token != TokenId::default() {208 return 0;209 }210 <Balance<T>>::get((self.id, account.as_sub()))211 }212213 fn allowance(214 &self,215 sender: T::CrossAccountId,216 spender: T::CrossAccountId,217 token: TokenId,218 ) -> u128 {219 if token != TokenId::default() {220 return 0;221 }222 <Allowance<T>>::get((self.id, sender.as_sub(), spender.as_sub()))223 }224}1use core::marker::PhantomData;23use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};4use nft_data_structs::TokenId;5use pallet_common::{6 CommonCollectionOperations, CommonWeightInfo, account::CrossAccountId, with_weight,7};8use sp_runtime::ArithmeticError;9use sp_std::{vec::Vec, vec};1011use crate::{12 Allowance, Balance, Config, Error, FungibleHandle, Pallet, SelfWeightOf, weights::WeightInfo,13};1415pub struct CommonWeights<T: Config>(PhantomData<T>);16impl<T: Config> CommonWeightInfo for CommonWeights<T> {17 fn create_item() -> Weight {18 <SelfWeightOf<T>>::create_item()19 }2021 fn create_multiple_items(_amount: u32) -> Weight {22 Self::create_item()23 }2425 fn burn_item() -> Weight {26 <SelfWeightOf<T>>::burn_item()27 }2829 fn transfer() -> Weight {30 <SelfWeightOf<T>>::transfer()31 }3233 fn approve() -> Weight {34 <SelfWeightOf<T>>::approve()35 }3637 fn transfer_from() -> Weight {38 <SelfWeightOf<T>>::transfer_from()39 }4041 fn burn_from() -> Weight {42 043 }4445 fn set_variable_metadata(_bytes: u32) -> Weight {46 // Error47 048 }49}5051impl<T: Config> CommonCollectionOperations<T> for FungibleHandle<T> {52 fn create_item(53 &self,54 sender: T::CrossAccountId,55 to: T::CrossAccountId,56 data: nft_data_structs::CreateItemData,57 ) -> DispatchResultWithPostInfo {58 match data {59 nft_data_structs::CreateItemData::Fungible(data) => with_weight(60 <Pallet<T>>::create_item(self, &sender, (to, data.value)),61 <CommonWeights<T>>::create_item(),62 ),63 _ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),64 }65 }6667 fn create_multiple_items(68 &self,69 sender: T::CrossAccountId,70 to: T::CrossAccountId,71 data: Vec<nft_data_structs::CreateItemData>,72 ) -> DispatchResultWithPostInfo {73 let mut sum: u128 = 0;74 for data in data {75 match data {76 nft_data_structs::CreateItemData::Fungible(data) => {77 sum = sum78 .checked_add(data.value)79 .ok_or(ArithmeticError::Overflow)?;80 }81 _ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),82 }83 }8485 with_weight(86 <Pallet<T>>::create_item(self, &sender, (to, sum)),87 <CommonWeights<T>>::create_item(),88 )89 }9091 fn burn_item(92 &self,93 sender: T::CrossAccountId,94 token: TokenId,95 amount: u128,96 ) -> DispatchResultWithPostInfo {97 ensure!(98 token == TokenId::default(),99 <Error<T>>::FungibleItemsHaveNoId100 );101102 with_weight(103 <Pallet<T>>::burn(self, &sender, amount),104 <CommonWeights<T>>::burn_item(),105 )106 }107108 fn transfer(109 &self,110 from: T::CrossAccountId,111 to: T::CrossAccountId,112 token: TokenId,113 amount: u128,114 ) -> DispatchResultWithPostInfo {115 ensure!(116 token == TokenId::default(),117 <Error<T>>::FungibleItemsHaveNoId118 );119120 with_weight(121 <Pallet<T>>::transfer(&self, &from, &to, amount),122 <CommonWeights<T>>::transfer(),123 )124 }125126 fn approve(127 &self,128 sender: T::CrossAccountId,129 spender: T::CrossAccountId,130 token: TokenId,131 amount: u128,132 ) -> DispatchResultWithPostInfo {133 ensure!(134 token == TokenId::default(),135 <Error<T>>::FungibleItemsHaveNoId136 );137138 with_weight(139 <Pallet<T>>::set_allowance(&self, &sender, &spender, amount),140 <CommonWeights<T>>::approve(),141 )142 }143144 fn transfer_from(145 &self,146 sender: T::CrossAccountId,147 from: T::CrossAccountId,148 to: T::CrossAccountId,149 token: TokenId,150 amount: u128,151 ) -> DispatchResultWithPostInfo {152 ensure!(153 token == TokenId::default(),154 <Error<T>>::FungibleItemsHaveNoId155 );156157 with_weight(158 <Pallet<T>>::transfer_from(&self, &sender, &from, &to, amount),159 <CommonWeights<T>>::transfer_from(),160 )161 }162163 fn burn_from(164 &self,165 sender: T::CrossAccountId,166 from: T::CrossAccountId,167 token: TokenId,168 amount: u128,169 ) -> DispatchResultWithPostInfo {170 ensure!(171 token == TokenId::default(),172 <Error<T>>::FungibleItemsHaveNoId173 );174175 with_weight(176 <Pallet<T>>::burn_from(&self, &sender, &from, amount),177 <CommonWeights<T>>::burn_from(),178 )179 }180181 fn set_variable_metadata(182 &self,183 _sender: T::CrossAccountId,184 _token: TokenId,185 _data: Vec<u8>,186 ) -> DispatchResultWithPostInfo {187 fail!(<Error<T>>::FungibleItemsHaveData)188 }189190 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {191 if <Balance<T>>::get((self.id, account.as_sub())) != 0 {192 vec![TokenId::default()]193 } else {194 vec![]195 }196 }197198 fn token_exists(&self, token: TokenId) -> bool {199 token == TokenId::default()200 }201202 fn last_token_id(&self) -> TokenId {203 TokenId::default()204 }205206 fn token_owner(&self, _token: TokenId) -> T::CrossAccountId {207 T::CrossAccountId::default()208 }209 fn const_metadata(&self, _token: TokenId) -> Vec<u8> {210 Vec::new()211 }212 fn variable_metadata(&self, _token: TokenId) -> Vec<u8> {213 Vec::new()214 }215216 fn collection_tokens(&self) -> u32 {217 1218 }219220 fn account_balance(&self, account: T::CrossAccountId) -> u32 {221 if <Balance<T>>::get((self.id, account.as_sub())) != 0 {222 1223 } else {224 0225 }226 }227228 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {229 if token != TokenId::default() {230 return 0;231 }232 <Balance<T>>::get((self.id, account.as_sub()))233 }234235 fn allowance(236 &self,237 sender: T::CrossAccountId,238 spender: T::CrossAccountId,239 token: TokenId,240 ) -> u128 {241 if token != TokenId::default() {242 return 0;243 }244 <Allowance<T>>::get((self.id, sender.as_sub(), spender.as_sub()))245 }246}pallets/fungible/src/erc.rsdiffbeforeafterboth--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -96,6 +96,18 @@
}
}
+#[solidity_interface(name = "ERC20UniqueExtensions")]
+impl<T: Config> FungibleHandle<T> {
+ fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let from = T::CrossAccountId::from_eth(from);
+ let amount = amount.try_into().map_err(|_| "amount overflow")?;
+
+ <Pallet<T>>::burn_from(self, &caller, &from, amount).map_err(dispatch_to_evm::<T>)?;
+ Ok(true)
+ }
+}
+
#[solidity_interface(name = "UniqueFungible", is(ERC20))]
impl<T: Config> FungibleHandle<T> {}
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -356,6 +356,38 @@
Ok(())
}
+ pub fn burn_from(
+ collection: &FungibleHandle<T>,
+ 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 = <Allowance<T>>::get((collection.id, from.as_sub(), spender.as_sub()))
+ .checked_sub(amount);
+ if allowance.is_none() {
+ ensure!(
+ collection.ignores_allowance(spender)?,
+ <CommonError<T>>::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<T>,
pallets/nft/src/common.rsdiffbeforeafterboth--- 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::<T>() + max_weight_of!(set_variable_metadata(bytes))
}
+
+ fn burn_from() -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(burn_from())
+ }
}
pallets/nft/src/eth/sponsoring.rsdiffbeforeafterboth--- 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 = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
pallets/nft/src/lib.rsdiffbeforeafterboth--- 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 = <CommonWeights<T>>::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::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value))
- // todo!()
- // }
+ dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value))
+ }
/// Change ownership of the token.
///
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -39,6 +39,10 @@
<SelfWeightOf<T>>::transfer_from()
}
+ fn burn_from() -> Weight {
+ 0
+ }
+
fn set_variable_metadata(bytes: u32) -> Weight {
<SelfWeightOf<T>>::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, <Error<T>>::NonfungibleItemsHaveNoAmount);
+
+ if amount == 1 {
+ with_weight(
+ <Pallet<T>>::burn_from(&self, &sender, &from, token),
+ <CommonWeights<T>>::burn_from(),
+ )
+ } else {
+ Ok(().into())
+ }
+ }
+
fn set_variable_metadata(
&self,
sender: T::CrossAccountId,
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -264,8 +264,7 @@
#[solidity_interface(name = "ERC721UniqueExtensions")]
impl<T: Config> NonfungibleHandle<T> {
- #[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<void> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let from = T::CrossAccountId::from_eth(from);
+ let token = token_id.try_into()?;
+
+ <Pallet<T>>::burn_from(self, &caller, &from, token).map_err(dispatch_to_evm::<T>)?;
+ Ok(())
+ }
+
fn next_token_id(&self) -> Result<uint256> {
Ok(<TokensMinted<T>>::get(self.id)
.checked_add(1)
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -499,6 +499,32 @@
Ok(())
}
+ pub fn burn_from(
+ collection: &NonfungibleHandle<T>,
+ 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 <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {
+ ensure!(
+ collection.ignores_allowance(spender)?,
+ <CommonError<T>>::TokenValueNotEnough
+ );
+ }
+
+ // =========
+
+ Self::burn(collection, &from, token)
+ }
+
pub fn set_variable_metadata(
collection: &NonfungibleHandle<T>,
sender: &T::CrossAccountId,
pallets/refungible/src/common.rsdiffbeforeafterboth--- 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 {
<SelfWeightOf<T>>::set_variable_metadata(bytes)
}
@@ -161,7 +165,20 @@
) -> DispatchResultWithPostInfo {
with_weight(
<Pallet<T>>::transfer_from(&self, &sender, &from, &to, token, amount),
- <CommonWeights<T>>::approve(),
+ <CommonWeights<T>>::transfer_from(),
+ )
+ }
+
+ fn burn_from(
+ &self,
+ sender: T::CrossAccountId,
+ from: T::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ ) -> DispatchResultWithPostInfo {
+ with_weight(
+ <Pallet<T>>::burn_from(&self, &sender, &from, token, amount),
+ <CommonWeights<T>>::burn_from(),
)
}
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -537,6 +537,39 @@
Ok(())
}
+ pub fn burn_from(
+ collection: &RefungibleHandle<T>,
+ 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 = <Allowance<T>>::get((collection.id, token, from.as_sub(), &spender))
+ .checked_sub(amount);
+ if allowance.is_none() {
+ ensure!(
+ collection.ignores_allowance(spender)?,
+ <CommonError<T>>::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<T>,
sender: &T::CrossAccountId,