difftreelog
fix revert set_allowance
in: master
8 files changed
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -1298,7 +1298,6 @@
spender: T::CrossAccountId,
token: TokenId,
amount: u128,
- nesting_budget: &dyn Budget,
) -> DispatchResultWithPostInfo;
fn transfer_from(
&self,
pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -226,7 +226,6 @@
spender: T::CrossAccountId,
token: TokenId,
amount: u128,
- _nesting_budget: &dyn Budget,
) -> DispatchResultWithPostInfo {
ensure!(
token == TokenId::default(),
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -308,15 +308,14 @@
spender: T::CrossAccountId,
token: TokenId,
amount: u128,
- nesting_budget: &dyn Budget,
) -> DispatchResultWithPostInfo {
ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
with_weight(
if amount == 1 {
- <Pallet<T>>::set_allowance(self, &sender, token, Some(&spender), nesting_budget)
+ <Pallet<T>>::set_allowance(self, &sender, token, Some(&spender))
} else {
- <Pallet<T>>::set_allowance(self, &sender, token, None, nesting_budget)
+ <Pallet<T>>::set_allowance(self, &sender, token, None)
},
<CommonWeights<T>>::approve(),
)
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -269,11 +269,8 @@
let caller = T::CrossAccountId::from_eth(caller);
let approved = T::CrossAccountId::from_eth(approved);
let token = token_id.try_into()?;
- let budget = self
- .recorder
- .weight_calls_budget(<StructureWeight<T>>::find_parent());
- <Pallet<T>>::set_allowance(self, &caller, token, Some(&approved), &budget)
+ <Pallet<T>>::set_allowance(self, &caller, token, Some(&approved))
.map_err(dispatch_to_evm::<T>)?;
Ok(())
}
pallets/nonfungible/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819use erc::ERC721Events;20use evm_coder::ToLog;21use frame_support::{22 BoundedVec, ensure, fail, transactional,23 storage::with_transaction,24 pallet_prelude::DispatchResultWithPostInfo,25 pallet_prelude::Weight,26 weights::{PostDispatchInfo, Pays},27};28use up_data_structs::{29 AccessMode, CollectionId, CustomDataLimit, TokenId, CreateCollectionData, CreateNftExData,30 mapping::TokenAddressMapping, NestingRule, budget::Budget, Property, PropertyPermission,31 PropertyKey, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty, TokenChild,32};33use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};34use pallet_common::{35 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle,36 eth::collection_id_to_address,37};38use pallet_structure::{Pallet as PalletStructure, Error as StructureError};39use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};40use sp_core::H160;41use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};42use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap, collections::btree_set::BTreeSet};43use core::ops::Deref;44use codec::{Encode, Decode, MaxEncodedLen};45use scale_info::TypeInfo;4647pub use pallet::*;48use weights::WeightInfo;49#[cfg(feature = "runtime-benchmarks")]50pub mod benchmarking;51pub mod common;52pub mod erc;53pub mod weights;5455pub type CreateItemData<T> = CreateNftExData<<T as pallet_evm::account::Config>::CrossAccountId>;56pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;5758#[struct_versioning::versioned(version = 2, upper)]59#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]60pub struct ItemData<CrossAccountId> {61 #[version(..2)]62 pub const_data: BoundedVec<u8, CustomDataLimit>,6364 #[version(..2)]65 pub variable_data: BoundedVec<u8, CustomDataLimit>,6667 pub owner: CrossAccountId,68}6970#[frame_support::pallet]71pub mod pallet {72 use super::*;73 use frame_support::{74 Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key, traits::StorageVersion,75 };76 use frame_system::pallet_prelude::*;77 use up_data_structs::{CollectionId, TokenId};78 use super::weights::WeightInfo;7980 #[pallet::error]81 pub enum Error<T> {82 /// Not Nonfungible item data used to mint in Nonfungible collection.83 NotNonfungibleDataUsedToMintFungibleCollectionToken,84 /// Used amount > 1 with NFT85 NonfungibleItemsHaveNoAmount,86 /// Unable to burn NFT with children87 CantBurnNftWithChildren,88 }8990 #[pallet::config]91 pub trait Config:92 frame_system::Config + pallet_common::Config + pallet_structure::Config + pallet_evm::Config93 {94 type WeightInfo: WeightInfo;95 }9697 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);9899 #[pallet::pallet]100 #[pallet::storage_version(STORAGE_VERSION)]101 #[pallet::generate_store(pub(super) trait Store)]102 pub struct Pallet<T>(_);103104 #[pallet::storage]105 pub type TokensMinted<T: Config> =106 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;107 #[pallet::storage]108 pub type TokensBurnt<T: Config> =109 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;110111 #[pallet::storage]112 pub type TokenData<T: Config> = StorageNMap<113 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),114 Value = ItemData<T::CrossAccountId>,115 QueryKind = OptionQuery,116 >;117118 #[pallet::storage]119 #[pallet::getter(fn token_properties)]120 pub type TokenProperties<T: Config> = StorageNMap<121 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),122 Value = Properties,123 QueryKind = ValueQuery,124 OnEmpty = up_data_structs::TokenProperties,125 >;126127 /// Used to enumerate tokens owned by account128 #[pallet::storage]129 pub type Owned<T: Config> = StorageNMap<130 Key = (131 Key<Twox64Concat, CollectionId>,132 Key<Blake2_128Concat, T::CrossAccountId>,133 Key<Twox64Concat, TokenId>,134 ),135 Value = bool,136 QueryKind = ValueQuery,137 >;138139 /// Used to enumerate token's children140 #[pallet::storage]141 #[pallet::getter(fn token_children)]142 pub type TokenChildren<T: Config> = StorageNMap<143 Key = (144 Key<Twox64Concat, CollectionId>,145 Key<Twox64Concat, TokenId>,146 Key<Twox64Concat, (CollectionId, TokenId)>,147 ),148 Value = bool,149 QueryKind = ValueQuery,150 >;151152 #[pallet::storage]153 pub type AccountBalance<T: Config> = StorageNMap<154 Key = (155 Key<Twox64Concat, CollectionId>,156 Key<Blake2_128Concat, T::CrossAccountId>,157 ),158 Value = u32,159 QueryKind = ValueQuery,160 >;161162 #[pallet::storage]163 pub type Allowance<T: Config> = StorageNMap<164 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),165 Value = T::CrossAccountId,166 QueryKind = OptionQuery,167 >;168169 #[pallet::hooks]170 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {171 fn on_runtime_upgrade() -> Weight {172 if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {173 let mut had_consts = BTreeSet::new();174 <TokenData<T>>::translate::<ItemDataVersion1<T::CrossAccountId>, _>(175 |(collection, token), v| {176 let mut props = vec![];177 if !v.const_data.is_empty() {178 props.push(Property {179 key: b"_old_constData".to_vec().try_into().unwrap(),180 value: v181 .const_data182 .clone()183 .into_inner()184 .try_into()185 .expect("const too long"),186 });187 had_consts.insert(collection);188 }189 if !v.variable_data.is_empty() {190 props.push(Property {191 key: b"_old_variableData".to_vec().try_into().unwrap(),192 value: v193 .variable_data194 .clone()195 .into_inner()196 .try_into()197 .expect("variable too long"),198 })199 }200 if !props.is_empty() {201 Self::set_scoped_token_properties(202 collection,203 token,204 PropertyScope::None,205 props.into_iter(),206 )207 .expect("existing token data exceeds property storage");208 }209 Some(<ItemDataVersion2<T::CrossAccountId>>::from(v))210 },211 );212 for collection in had_consts {213 <PalletCommon<T>>::set_property_permission_unchecked(214 collection,215 PropertyKeyPermission {216 key: b"_old_constData".to_vec().try_into().unwrap(),217 permission: PropertyPermission {218 mutable: false,219 collection_admin: true,220 token_owner: false,221 },222 },223 )224 .expect("failed to configure permission");225 }226 }227228 0229 }230 }231}232233pub struct NonfungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);234impl<T: Config> NonfungibleHandle<T> {235 pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {236 Self(inner)237 }238 pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {239 self.0240 }241 pub fn common_mut(&mut self) -> &mut pallet_common::CollectionHandle<T> {242 &mut self.0243 }244}245impl<T: Config> WithRecorder<T> for NonfungibleHandle<T> {246 fn recorder(&self) -> &SubstrateRecorder<T> {247 self.0.recorder()248 }249 fn into_recorder(self) -> SubstrateRecorder<T> {250 self.0.into_recorder()251 }252}253impl<T: Config> Deref for NonfungibleHandle<T> {254 type Target = pallet_common::CollectionHandle<T>;255256 fn deref(&self) -> &Self::Target {257 &self.0258 }259}260261impl<T: Config> Pallet<T> {262 pub fn total_supply(collection: &NonfungibleHandle<T>) -> u32 {263 <TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)264 }265 pub fn token_exists(collection: &NonfungibleHandle<T>, token: TokenId) -> bool {266 <TokenData<T>>::contains_key((collection.id, token))267 }268269 pub fn set_scoped_token_property(270 collection_id: CollectionId,271 token_id: TokenId,272 scope: PropertyScope,273 property: Property,274 ) -> DispatchResult {275 TokenProperties::<T>::try_mutate((collection_id, token_id), |properties| {276 properties.try_scoped_set(scope, property.key, property.value)277 })278 .map_err(<CommonError<T>>::from)?;279280 Ok(())281 }282283 pub fn set_scoped_token_properties(284 collection_id: CollectionId,285 token_id: TokenId,286 scope: PropertyScope,287 properties: impl Iterator<Item = Property>,288 ) -> DispatchResult {289 TokenProperties::<T>::try_mutate((collection_id, token_id), |stored_properties| {290 stored_properties.try_scoped_set_from_iter(scope, properties)291 })292 .map_err(<CommonError<T>>::from)?;293294 Ok(())295 }296297 pub fn current_token_id(collection_id: CollectionId) -> TokenId {298 TokenId(<TokensMinted<T>>::get(collection_id))299 }300}301302// unchecked calls skips any permission checks303impl<T: Config> Pallet<T> {304 pub fn init_collection(305 owner: T::CrossAccountId,306 data: CreateCollectionData<T::AccountId>,307 ) -> Result<CollectionId, DispatchError> {308 <PalletCommon<T>>::init_collection(owner, data)309 }310 pub fn destroy_collection(311 collection: NonfungibleHandle<T>,312 sender: &T::CrossAccountId,313 ) -> DispatchResult {314 let id = collection.id;315316 if Self::collection_has_tokens(id) {317 return Err(<CommonError<T>>::CantDestroyNotEmptyCollection.into());318 }319320 // =========321322 PalletCommon::destroy_collection(collection.0, sender)?;323324 <TokenData<T>>::remove_prefix((id,), None);325 <TokenChildren<T>>::remove_prefix((id,), None);326 <Owned<T>>::remove_prefix((id,), None);327 <TokensMinted<T>>::remove(id);328 <TokensBurnt<T>>::remove(id);329 <Allowance<T>>::remove_prefix((id,), None);330 <AccountBalance<T>>::remove_prefix((id,), None);331 Ok(())332 }333334 pub fn burn(335 collection: &NonfungibleHandle<T>,336 sender: &T::CrossAccountId,337 token: TokenId,338 ) -> DispatchResult {339 let token_data =340 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;341 ensure!(342 &token_data.owner == sender343 || (collection.limits.owner_can_transfer() && collection.is_owner_or_admin(sender)),344 <CommonError<T>>::NoPermission345 );346347 if collection.permissions.access() == AccessMode::AllowList {348 collection.check_allowlist(sender)?;349 }350351 if Self::token_has_children(collection.id, token) {352 return Err(<Error<T>>::CantBurnNftWithChildren.into());353 }354355 let burnt = <TokensBurnt<T>>::get(collection.id)356 .checked_add(1)357 .ok_or(ArithmeticError::Overflow)?;358359 let balance = <AccountBalance<T>>::get((collection.id, token_data.owner.clone()))360 .checked_sub(1)361 .ok_or(ArithmeticError::Overflow)?;362363 // =========364365 if balance == 0 {366 <AccountBalance<T>>::remove((collection.id, token_data.owner.clone()));367 } else {368 <AccountBalance<T>>::insert((collection.id, token_data.owner.clone()), balance);369 }370371 <PalletStructure<T>>::unnest_if_nested(&token_data.owner, collection.id, token);372373 <Owned<T>>::remove((collection.id, &token_data.owner, token));374 <TokensBurnt<T>>::insert(collection.id, burnt);375 <TokenData<T>>::remove((collection.id, token));376 <TokenProperties<T>>::remove((collection.id, token));377 let old_spender = <Allowance<T>>::take((collection.id, token));378379 if let Some(old_spender) = old_spender {380 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(381 collection.id,382 token,383 token_data.owner.clone(),384 old_spender,385 0,386 ));387 }388389 <PalletEvm<T>>::deposit_log(390 ERC721Events::Transfer {391 from: *token_data.owner.as_eth(),392 to: H160::default(),393 token_id: token.into(),394 }395 .to_log(collection_id_to_address(collection.id)),396 );397 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(398 collection.id,399 token,400 token_data.owner,401 1,402 ));403 Ok(())404 }405406 #[transactional]407 pub fn burn_recursively(408 collection: &NonfungibleHandle<T>,409 sender: &T::CrossAccountId,410 token: TokenId,411 self_budget: &dyn Budget,412 breadth_budget: &dyn Budget,413 ) -> DispatchResultWithPostInfo {414 ensure!(self_budget.consume(), <StructureError<T>>::DepthLimit,);415416 let current_token_account =417 T::CrossTokenAddressMapping::token_to_address(collection.id, token);418419 let mut weight = 0 as Weight;420421 // This method is transactional, if user in fact doesn't have permissions to remove token -422 // tokens removed here will be restored after rejected transaction423 for ((collection, token), _) in <TokenChildren<T>>::iter_prefix((collection.id, token)) {424 ensure!(breadth_budget.consume(), <StructureError<T>>::BreadthLimit,);425 let PostDispatchInfo { actual_weight, .. } =426 <PalletStructure<T>>::burn_item_recursively(427 current_token_account.clone(),428 collection,429 token,430 self_budget,431 breadth_budget,432 )?;433 if let Some(actual_weight) = actual_weight {434 weight = weight.saturating_add(actual_weight);435 }436 }437438 Self::burn(collection, sender, token)?;439 DispatchResultWithPostInfo::Ok(PostDispatchInfo {440 actual_weight: Some(weight + <SelfWeightOf<T>>::burn_item()),441 pays_fee: Pays::Yes,442 })443 }444445 pub fn set_token_property(446 collection: &NonfungibleHandle<T>,447 sender: &T::CrossAccountId,448 token_id: TokenId,449 property: Property,450 ) -> DispatchResult {451 Self::check_token_change_permission(collection, sender, token_id, &property.key)?;452453 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {454 let property = property.clone();455 properties.try_set(property.key, property.value)456 })457 .map_err(<CommonError<T>>::from)?;458459 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(460 collection.id,461 token_id,462 property.key,463 ));464465 Ok(())466 }467468 #[transactional]469 pub fn set_token_properties(470 collection: &NonfungibleHandle<T>,471 sender: &T::CrossAccountId,472 token_id: TokenId,473 properties: Vec<Property>,474 ) -> DispatchResult {475 for property in properties {476 Self::set_token_property(collection, sender, token_id, property)?;477 }478479 Ok(())480 }481482 pub fn delete_token_property(483 collection: &NonfungibleHandle<T>,484 sender: &T::CrossAccountId,485 token_id: TokenId,486 property_key: PropertyKey,487 ) -> DispatchResult {488 Self::check_token_change_permission(collection, sender, token_id, &property_key)?;489490 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {491 properties.remove(&property_key)492 })493 .map_err(<CommonError<T>>::from)?;494495 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(496 collection.id,497 token_id,498 property_key,499 ));500501 Ok(())502 }503504 fn check_token_change_permission(505 collection: &NonfungibleHandle<T>,506 sender: &T::CrossAccountId,507 token_id: TokenId,508 property_key: &PropertyKey,509 ) -> DispatchResult {510 let permission = <PalletCommon<T>>::property_permissions(collection.id)511 .get(property_key)512 .cloned()513 .unwrap_or_else(PropertyPermission::none);514515 let token_data = <TokenData<T>>::get((collection.id, token_id))516 .ok_or(<CommonError<T>>::TokenNotFound)?;517518 let check_token_owner = || -> DispatchResult {519 ensure!(&token_data.owner == sender, <CommonError<T>>::NoPermission);520 Ok(())521 };522523 let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))524 .get(property_key)525 .is_some();526527 match permission {528 PropertyPermission { mutable: false, .. } if is_property_exists => {529 Err(<CommonError<T>>::NoPermission.into())530 }531532 PropertyPermission {533 collection_admin,534 token_owner,535 ..536 } => {537 let mut check_result = Err(<CommonError<T>>::NoPermission.into());538539 if collection_admin {540 check_result = collection.check_is_owner_or_admin(sender);541 }542543 if token_owner {544 check_result.or_else(|_| check_token_owner())545 } else {546 check_result547 }548 }549 }550 }551552 #[transactional]553 pub fn delete_token_properties(554 collection: &NonfungibleHandle<T>,555 sender: &T::CrossAccountId,556 token_id: TokenId,557 property_keys: Vec<PropertyKey>,558 ) -> DispatchResult {559 for key in property_keys {560 Self::delete_token_property(collection, sender, token_id, key)?;561 }562563 Ok(())564 }565566 pub fn set_collection_properties(567 collection: &NonfungibleHandle<T>,568 sender: &T::CrossAccountId,569 properties: Vec<Property>,570 ) -> DispatchResult {571 <PalletCommon<T>>::set_collection_properties(collection, sender, properties)572 }573574 pub fn delete_collection_properties(575 collection: &CollectionHandle<T>,576 sender: &T::CrossAccountId,577 property_keys: Vec<PropertyKey>,578 ) -> DispatchResult {579 <PalletCommon<T>>::delete_collection_properties(collection, sender, property_keys)580 }581582 pub fn set_property_permissions(583 collection: &CollectionHandle<T>,584 sender: &T::CrossAccountId,585 property_permissions: Vec<PropertyKeyPermission>,586 ) -> DispatchResult {587 <PalletCommon<T>>::set_property_permissions(collection, sender, property_permissions)588 }589590 pub fn set_property_permission(591 collection: &CollectionHandle<T>,592 sender: &T::CrossAccountId,593 permission: PropertyKeyPermission,594 ) -> DispatchResult {595 <PalletCommon<T>>::set_property_permission(collection, sender, permission)596 }597598 pub fn transfer(599 collection: &NonfungibleHandle<T>,600 from: &T::CrossAccountId,601 to: &T::CrossAccountId,602 token: TokenId,603 nesting_budget: &dyn Budget,604 ) -> DispatchResult {605 ensure!(606 collection.limits.transfers_enabled(),607 <CommonError<T>>::TransferNotAllowed608 );609610 let token_data =611 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;612 // TODO: require sender to be token, owner, require admins to go through transfer_from613 ensure!(614 &token_data.owner == from615 || (collection.limits.owner_can_transfer() && collection.is_owner_or_admin(from)),616 <CommonError<T>>::NoPermission617 );618619 if collection.permissions.access() == AccessMode::AllowList {620 collection.check_allowlist(from)?;621 collection.check_allowlist(to)?;622 }623 <PalletCommon<T>>::ensure_correct_receiver(to)?;624625 let balance_from = <AccountBalance<T>>::get((collection.id, from))626 .checked_sub(1)627 .ok_or(<CommonError<T>>::TokenValueTooLow)?;628 let balance_to = if from != to {629 let balance_to = <AccountBalance<T>>::get((collection.id, to))630 .checked_add(1)631 .ok_or(ArithmeticError::Overflow)?;632633 ensure!(634 balance_to < collection.limits.account_token_ownership_limit(),635 <CommonError<T>>::AccountTokenLimitExceeded,636 );637638 Some(balance_to)639 } else {640 None641 };642643 <PalletStructure<T>>::nest_if_sent_to_token(644 from.clone(),645 to,646 collection.id,647 token,648 nesting_budget,649 )?;650651 // =========652653 <PalletStructure<T>>::unnest_if_nested(&token_data.owner, collection.id, token);654655 <TokenData<T>>::insert(656 (collection.id, token),657 ItemData {658 owner: to.clone(),659 ..token_data660 },661 );662663 if let Some(balance_to) = balance_to {664 // from != to665 if balance_from == 0 {666 <AccountBalance<T>>::remove((collection.id, from));667 } else {668 <AccountBalance<T>>::insert((collection.id, from), balance_from);669 }670 <AccountBalance<T>>::insert((collection.id, to), balance_to);671 <Owned<T>>::remove((collection.id, from, token));672 <Owned<T>>::insert((collection.id, to, token), true);673 }674 Self::set_allowance_unchecked(collection, from, token, None, true);675676 <PalletEvm<T>>::deposit_log(677 ERC721Events::Transfer {678 from: *from.as_eth(),679 to: *to.as_eth(),680 token_id: token.into(),681 }682 .to_log(collection_id_to_address(collection.id)),683 );684 <PalletCommon<T>>::deposit_event(CommonEvent::Transfer(685 collection.id,686 token,687 from.clone(),688 to.clone(),689 1,690 ));691 Ok(())692 }693694 pub fn create_multiple_items(695 collection: &NonfungibleHandle<T>,696 sender: &T::CrossAccountId,697 data: Vec<CreateItemData<T>>,698 nesting_budget: &dyn Budget,699 ) -> DispatchResult {700 if !collection.is_owner_or_admin(sender) {701 ensure!(702 collection.permissions.mint_mode(),703 <CommonError<T>>::PublicMintingNotAllowed704 );705 collection.check_allowlist(sender)?;706707 for item in data.iter() {708 collection.check_allowlist(&item.owner)?;709 }710 }711712 for data in data.iter() {713 <PalletCommon<T>>::ensure_correct_receiver(&data.owner)?;714 }715716 let first_token = <TokensMinted<T>>::get(collection.id);717 let tokens_minted = first_token718 .checked_add(data.len() as u32)719 .ok_or(ArithmeticError::Overflow)?;720 ensure!(721 tokens_minted <= collection.limits.token_limit(),722 <CommonError<T>>::CollectionTokenLimitExceeded723 );724725 let mut balances = BTreeMap::new();726 for data in &data {727 let balance = balances728 .entry(&data.owner)729 .or_insert_with(|| <AccountBalance<T>>::get((collection.id, &data.owner)));730 *balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?;731732 ensure!(733 *balance <= collection.limits.account_token_ownership_limit(),734 <CommonError<T>>::AccountTokenLimitExceeded,735 );736 }737738 for (i, data) in data.iter().enumerate() {739 let token = TokenId(first_token + i as u32 + 1);740741 <PalletStructure<T>>::check_nesting(742 sender.clone(),743 &data.owner,744 collection.id,745 token,746 nesting_budget,747 )?;748 }749750 // =========751752 with_transaction(|| {753 for (i, data) in data.iter().enumerate() {754 let token = first_token + i as u32 + 1;755756 <TokenData<T>>::insert(757 (collection.id, token),758 ItemData {759 // const_data: data.const_data.clone(),760 owner: data.owner.clone(),761 },762 );763764 <PalletStructure<T>>::nest_if_sent_to_token_unchecked(765 &data.owner,766 collection.id,767 TokenId(token),768 );769770 if let Err(e) = Self::set_token_properties(771 collection,772 sender,773 TokenId(token),774 data.properties.clone().into_inner(),775 ) {776 return TransactionOutcome::Rollback(Err(e));777 }778 }779 TransactionOutcome::Commit(Ok(()))780 })?;781782 <TokensMinted<T>>::insert(collection.id, tokens_minted);783 for (account, balance) in balances {784 <AccountBalance<T>>::insert((collection.id, account), balance);785 }786 for (i, data) in data.into_iter().enumerate() {787 let token = first_token + i as u32 + 1;788 <Owned<T>>::insert((collection.id, &data.owner, token), true);789790 <PalletEvm<T>>::deposit_log(791 ERC721Events::Transfer {792 from: H160::default(),793 to: *data.owner.as_eth(),794 token_id: token.into(),795 }796 .to_log(collection_id_to_address(collection.id)),797 );798 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(799 collection.id,800 TokenId(token),801 data.owner.clone(),802 1,803 ));804 }805 Ok(())806 }807808 pub fn set_allowance_unchecked(809 collection: &NonfungibleHandle<T>,810 sender: &T::CrossAccountId,811 token: TokenId,812 spender: Option<&T::CrossAccountId>,813 assume_implicit_eth: bool,814 ) {815 if let Some(spender) = spender {816 let old_spender = <Allowance<T>>::get((collection.id, token));817 <Allowance<T>>::insert((collection.id, token), spender);818 // In ERC721 there is only one possible approved user of token, so we set819 // approved user to spender820 <PalletEvm<T>>::deposit_log(821 ERC721Events::Approval {822 owner: *sender.as_eth(),823 approved: *spender.as_eth(),824 token_id: token.into(),825 }826 .to_log(collection_id_to_address(collection.id)),827 );828 // In Unique chain, any token can have any amount of approved users, so we need to829 // set allowance of old owner to 0, and allowance of new owner to 1830 if old_spender.as_ref() != Some(spender) {831 if let Some(old_owner) = old_spender {832 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(833 collection.id,834 token,835 sender.clone(),836 old_owner,837 0,838 ));839 }840 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(841 collection.id,842 token,843 sender.clone(),844 spender.clone(),845 1,846 ));847 }848 } else {849 let old_spender = <Allowance<T>>::take((collection.id, token));850 if !assume_implicit_eth {851 // In ERC721 there is only one possible approved user of token, so we set852 // approved user to zero address853 <PalletEvm<T>>::deposit_log(854 ERC721Events::Approval {855 owner: *sender.as_eth(),856 approved: H160::default(),857 token_id: token.into(),858 }859 .to_log(collection_id_to_address(collection.id)),860 );861 }862 // In Unique chain, any token can have any amount of approved users, so we need to863 // set allowance of old owner to 0864 if let Some(old_spender) = old_spender {865 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(866 collection.id,867 token,868 sender.clone(),869 old_spender,870 0,871 ));872 }873 }874 }875876 pub fn set_allowance(877 collection: &NonfungibleHandle<T>,878 sender: &T::CrossAccountId,879 token: TokenId,880 spender: Option<&T::CrossAccountId>,881 nesting_budget: &dyn Budget,882 ) -> DispatchResult {883 if collection.permissions.access() == AccessMode::AllowList {884 collection.check_allowlist(sender)?;885 if let Some(spender) = spender {886 collection.check_allowlist(spender)?;887 }888 }889890 if let Some(spender) = spender {891 <PalletCommon<T>>::ensure_correct_receiver(spender)?;892 }893894 let is_owned = <PalletStructure<T>>::check_indirectly_owned(895 sender.clone(),896 collection.id,897 token,898 None,899 nesting_budget900 )?;901902 if !is_owned {903 ensure!(904 collection.ignores_owned_amount(sender),905 <CommonError<T>>::CantApproveMoreThanOwned906 );907 }908909 // =========910911 Self::set_allowance_unchecked(collection, sender, token, spender, false);912 Ok(())913 }914915 fn check_allowed(916 collection: &NonfungibleHandle<T>,917 spender: &T::CrossAccountId,918 from: &T::CrossAccountId,919 token: TokenId,920 nesting_budget: &dyn Budget,921 ) -> DispatchResult {922 if spender.conv_eq(from) {923 return Ok(());924 }925 if collection.permissions.access() == AccessMode::AllowList {926 // `from`, `to` checked in [`transfer`]927 collection.check_allowlist(spender)?;928 }929 if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {930 return Ok(());931 }932 if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {933 // TODO: should collection owner be allowed to perform this transfer?934 ensure!(935 <PalletStructure<T>>::check_indirectly_owned(936 spender.clone(),937 source.0,938 source.1,939 None,940 nesting_budget941 )?,942 <CommonError<T>>::ApprovedValueTooLow,943 );944 return Ok(());945 }946 ensure!(947 collection.ignores_allowance(spender),948 <CommonError<T>>::ApprovedValueTooLow949 );950 Ok(())951 }952953 pub fn transfer_from(954 collection: &NonfungibleHandle<T>,955 spender: &T::CrossAccountId,956 from: &T::CrossAccountId,957 to: &T::CrossAccountId,958 token: TokenId,959 nesting_budget: &dyn Budget,960 ) -> DispatchResult {961 Self::check_allowed(collection, spender, from, token, nesting_budget)?;962963 // =========964965 // Allowance is reset in [`transfer`]966 Self::transfer(collection, from, to, token, nesting_budget)967 }968969 pub fn burn_from(970 collection: &NonfungibleHandle<T>,971 spender: &T::CrossAccountId,972 from: &T::CrossAccountId,973 token: TokenId,974 nesting_budget: &dyn Budget,975 ) -> DispatchResult {976 Self::check_allowed(collection, spender, from, token, nesting_budget)?;977978 // =========979980 Self::burn(collection, from, token)981 }982983 pub fn check_nesting(984 handle: &NonfungibleHandle<T>,985 sender: T::CrossAccountId,986 from: (CollectionId, TokenId),987 under: TokenId,988 nesting_budget: &dyn Budget,989 ) -> DispatchResult {990 fn ensure_sender_allowed<T: Config>(991 collection: CollectionId,992 token: TokenId,993 for_nest: (CollectionId, TokenId),994 sender: T::CrossAccountId,995 budget: &dyn Budget,996 ) -> DispatchResult {997 ensure!(998 <PalletStructure<T>>::check_indirectly_owned(999 sender,1000 collection,1001 token,1002 Some(for_nest),1003 budget1004 )?,1005 <CommonError<T>>::OnlyOwnerAllowedToNest,1006 );1007 Ok(())1008 }1009 match handle.permissions.nesting() {1010 NestingRule::Disabled => fail!(<CommonError<T>>::NestingIsDisabled),1011 NestingRule::Owner => {1012 ensure_sender_allowed::<T>(handle.id, under, from, sender, nesting_budget)?1013 }1014 NestingRule::OwnerRestricted(whitelist) => {1015 ensure!(1016 whitelist.contains(&from.0),1017 <CommonError<T>>::SourceCollectionIsNotAllowedToNest1018 );1019 ensure_sender_allowed::<T>(handle.id, under, from, sender, nesting_budget)?1020 }1021 NestingRule::Permissive => {}1022 }1023 Ok(())1024 }10251026 fn nest(under: (CollectionId, TokenId), to_nest: (CollectionId, TokenId)) {1027 <TokenChildren<T>>::insert((under.0, under.1, (to_nest.0, to_nest.1)), true);1028 }10291030 fn unnest(under: (CollectionId, TokenId), to_unnest: (CollectionId, TokenId)) {1031 <TokenChildren<T>>::remove((under.0, under.1, to_unnest));1032 }10331034 fn collection_has_tokens(collection_id: CollectionId) -> bool {1035 <TokenData<T>>::iter_prefix((collection_id,))1036 .next()1037 .is_some()1038 }10391040 fn token_has_children(collection_id: CollectionId, token_id: TokenId) -> bool {1041 <TokenChildren<T>>::iter_prefix((collection_id, token_id))1042 .next()1043 .is_some()1044 }10451046 pub fn token_children_ids(collection_id: CollectionId, token_id: TokenId) -> Vec<TokenChild> {1047 <TokenChildren<T>>::iter_prefix((collection_id, token_id))1048 .map(|((child_collection_id, child_id), _)| TokenChild {1049 collection: child_collection_id,1050 token: child_id,1051 })1052 .collect()1053 }10541055 /// Delegated to `create_multiple_items`1056 pub fn create_item(1057 collection: &NonfungibleHandle<T>,1058 sender: &T::CrossAccountId,1059 data: CreateItemData<T>,1060 nesting_budget: &dyn Budget,1061 ) -> DispatchResult {1062 Self::create_multiple_items(collection, sender, vec![data], nesting_budget)1063 }1064}pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -414,13 +414,14 @@
let is_approval_required = cross_sender != spender;
if is_approval_required {
- <PalletNft<T>>::set_allowance(
- &collection,
- &cross_sender,
- nft_id,
- Some(&spender),
- &budget
- ).map_err(Self::map_common_err_to_proxy)?;
+ // FIXME
+ // <PalletNft<T>>::set_allowance(
+ // &collection,
+ // &cross_sender,
+ // nft_id,
+ // Some(&spender),
+ // &budget
+ // ).map_err(Self::map_common_err_to_proxy)?;
return Ok(());
}
pallets/refungible/src/common.rsdiffbeforeafterboth--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -254,7 +254,6 @@
spender: T::CrossAccountId,
token: TokenId,
amount: u128,
- _nesting_budget: &dyn Budget,
) -> DispatchResultWithPostInfo {
with_weight(
<Pallet<T>>::set_allowance(self, &sender, &spender, token, amount),
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -815,9 +815,8 @@
#[transactional]
pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {
let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
- let budget = budget::Value::new(NESTING_BUDGET);
- dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount, &budget))
+ dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))
}
/// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.