--- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -34,7 +34,7 @@ use frame_system::{self as system, ensure_signed, ensure_root}; use sp_core::H160; use sp_std::vec; -use sp_runtime::sp_std::prelude::Vec; +use sp_runtime::{DispatchError, sp_std::prelude::Vec}; use core::ops::{Deref, DerefMut}; use nft_data_structs::{ MAX_DECIMAL_POINTS, MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP, MAX_REFUNGIBLE_PIECES, @@ -202,9 +202,16 @@ pub fn log(&self, log: impl evm_coder::ToLog) -> DispatchResult { self.recorder.log_sub(log) } + #[allow(dead_code)] fn consume_gas(&self, gas: u64) -> DispatchResult { self.recorder.consume_gas_sub(gas) } + fn consume_sload(&self) -> DispatchResult { + self.recorder.consume_sload_sub() + } + fn consume_sstore(&self) -> DispatchResult { + self.recorder.consume_sstore_sub() + } pub fn submit_logs(self) -> DispatchResult { self.recorder.submit_logs() } @@ -1276,14 +1283,13 @@ item_id: TokenId, value: u128, ) -> DispatchResult { - target_collection.consume_gas(2000000)?; // Limits check Self::is_correct_transfer(target_collection, recipient)?; // Transfer permissions check ensure!( - Self::is_item_owner(sender, target_collection, item_id) - || Self::is_owner_or_admin_permissions(target_collection, sender), + Self::is_item_owner(sender, target_collection, item_id)? + || Self::is_owner_or_admin_permissions(target_collection, sender)?, Error::::NoPermission ); @@ -1330,16 +1336,15 @@ item_id: TokenId, amount: u128, ) -> DispatchResult { - collection.consume_gas(2000000)?; Self::token_exists(collection, item_id)?; // Transfer permissions check let bypasses_limits = collection.limits.owner_can_transfer - && Self::is_owner_or_admin_permissions(collection, sender); + && Self::is_owner_or_admin_permissions(collection, sender)?; let allowance_limit = if bypasses_limits { None - } else if let Some(amount) = Self::owned_amount(sender, collection, item_id) { + } else if let Some(amount) = Self::owned_amount(sender, collection, item_id)? { Some(amount) } else { fail!(Error::::NoPermission); @@ -1350,6 +1355,7 @@ Self::check_white_list(collection, spender)?; } + collection.consume_sload()?; let allowance: u128 = amount .checked_add(>::get( collection.id, @@ -1359,6 +1365,7 @@ if let Some(limit) = allowance_limit { ensure!(limit >= allowance, Error::::TokenValueTooLow); } + collection.consume_sstore()?; >::insert( collection.id, (item_id, sender.as_sub(), spender.as_sub()), @@ -1401,8 +1408,8 @@ item_id: TokenId, amount: u128, ) -> DispatchResult { - collection.consume_gas(2000000)?; // Check approval + collection.consume_sload()?; let approval: u128 = >::get(collection.id, (item_id, from.as_sub(), sender.as_sub())); @@ -1413,7 +1420,7 @@ ensure!( approval >= amount || (collection.limits.owner_can_transfer - && Self::is_owner_or_admin_permissions(collection, sender)), + && Self::is_owner_or_admin_permissions(collection, sender)?), Error::::NoPermission ); @@ -1424,6 +1431,7 @@ // Reduce approval by transferred amount or remove if remaining approval drops to 0 let allowance = approval.saturating_sub(amount); + collection.consume_sstore()?; if allowance > 0 { >::insert( collection.id, @@ -1477,8 +1485,8 @@ // Modify permissions check ensure!( - Self::is_item_owner(sender, collection, item_id) - || Self::is_owner_or_admin_permissions(collection, sender), + Self::is_item_owner(sender, collection, item_id)? + || Self::is_owner_or_admin_permissions(collection, sender)?, Error::::NoPermission ); @@ -1519,9 +1527,9 @@ value: u128, ) -> DispatchResult { ensure!( - Self::is_item_owner(sender, collection, item_id) + Self::is_item_owner(sender, collection, item_id)? || (collection.limits.owner_can_transfer - && Self::is_owner_or_admin_permissions(collection, sender)), + && Self::is_owner_or_admin_permissions(collection, sender)?), Error::::NoPermission ); @@ -1563,6 +1571,7 @@ let collection_id = collection.id; // check token limit and account token limit + collection.consume_sload()?; let account_items: u32 = >::get(collection_id, recipient.as_sub()).len() as u32; ensure!( @@ -1601,7 +1610,7 @@ Error::::AccountTokenLimitExceeded ); - if !Self::is_owner_or_admin_permissions(collection, sender) { + if !Self::is_owner_or_admin_permissions(collection, sender)? { ensure!(collection.mint_mode, Error::::PublicMintingNotAllowed); Self::check_white_list(collection, owner)?; Self::check_white_list(collection, sender)?; @@ -1711,20 +1720,29 @@ let collection_id = collection.id; // Does new owner already have an account? + collection.consume_sload()?; let balance: u128 = >::get(collection_id, owner.as_sub()).value; // Mint let item = FungibleItemType { value: balance.checked_add(value).ok_or(Error::::NumOverflow)?, }; + collection.consume_sstore()?; >::insert(collection_id, owner.as_sub(), item); // Update balance + collection.consume_sload()?; let new_balance = >::get(collection_id, owner.as_sub()) .checked_add(value) .ok_or(Error::::NumOverflow)?; + collection.consume_sstore()?; >::insert(collection_id, owner.as_sub(), new_balance); + collection.log(ERC20Events::Transfer { + from: H160::default(), + to: *owner.as_eth(), + value: value.into(), + })?; Self::deposit_event(RawEvent::ItemCreated(collection_id, 0, owner.clone())); Ok(()) } @@ -1746,7 +1764,7 @@ let value = item_owner.fraction; let owner = item_owner.owner.clone(); - Self::add_token_index(collection_id, current_index, &owner)?; + Self::add_token_index(collection, current_index, &owner)?; ::insert(collection_id, current_index); >::insert(collection_id, current_index, itemcopy); @@ -1772,7 +1790,7 @@ .ok_or(Error::::NumOverflow)?; let item_owner = item.owner.clone(); - Self::add_token_index(collection_id, current_index, &item.owner)?; + Self::add_token_index(collection, current_index, &item.owner)?; ::insert(collection_id, current_index); >::insert(collection_id, current_index, item); @@ -1810,7 +1828,7 @@ .iter() .find(|&i| i.owner == *owner) .ok_or(Error::::TokenNotFound)?; - Self::remove_token_index(collection_id, item_id, owner)?; + Self::remove_token_index(collection, item_id, owner)?; // update balance let new_balance = >::get(collection_id, rft_balance.owner.as_sub()) @@ -1843,7 +1861,7 @@ let item = >::get(collection_id, item_id).ok_or(Error::::TokenNotFound)?; - Self::remove_token_index(collection_id, item_id, &item.owner)?; + Self::remove_token_index(collection, item_id, &item.owner)?; // update balance let new_balance = >::get(collection_id, item.owner.as_sub()) @@ -1909,9 +1927,10 @@ fn is_owner_or_admin_permissions( collection: &CollectionHandle, subject: &T::CrossAccountId, - ) -> bool { - *subject.as_sub() == collection.owner - || >::get(collection.id).contains(subject) + ) -> Result { + collection.consume_sload()?; + Ok(*subject.as_sub() == collection.owner + || >::get(collection.id).contains(subject)) } fn check_owner_or_admin_permissions( @@ -1919,7 +1938,7 @@ subject: &T::CrossAccountId, ) -> DispatchResult { ensure!( - Self::is_owner_or_admin_permissions(collection, subject), + Self::is_owner_or_admin_permissions(collection, subject)?, Error::::NoPermission ); @@ -1928,6 +1947,15 @@ fn owned_amount( subject: &T::CrossAccountId, + collection: &CollectionHandle, + item_id: TokenId, + ) -> Result, DispatchError> { + collection.consume_sload()?; + Ok(Self::owned_amount_unchecked(subject, collection, item_id)) + } + + fn owned_amount_unchecked( + subject: &T::CrossAccountId, target_collection: &CollectionHandle, item_id: TokenId, ) -> Option { @@ -1953,25 +1981,22 @@ subject: &T::CrossAccountId, target_collection: &CollectionHandle, item_id: TokenId, - ) -> bool { - match target_collection.mode { + ) -> Result { + Ok(match target_collection.mode { CollectionMode::Fungible(_) => true, - _ => Self::owned_amount(subject, target_collection, item_id).is_some(), - } + _ => Self::owned_amount(subject, target_collection, item_id)?.is_some(), + }) } fn check_white_list( collection: &CollectionHandle, address: &T::CrossAccountId, ) -> DispatchResult { - let collection_id = collection.id; - - let mes = Error::::AddresNotInWhiteList; + collection.consume_sload()?; ensure!( - >::contains_key(collection_id, address.as_sub()), - mes + >::contains_key(collection.id, address.as_sub()), + Error::::AddresNotInWhiteList, ); - Ok(()) } @@ -2000,6 +2025,7 @@ ) -> DispatchResult { let collection_id = collection.id; + collection.consume_sload()?; let mut balance = >::get(collection_id, owner.as_sub()); ensure!(balance.value >= value, Error::::TokenValueTooLow); @@ -2007,9 +2033,11 @@ Self::add_fungible_item(collection, recipient, value)?; // update balanceOf of sender + collection.consume_sstore()?; >::insert(collection_id, owner.as_sub(), balance.value - value); // Reduce or remove sender + collection.consume_sstore()?; if balance.value == value { >::remove(collection_id, owner.as_sub()); } else { @@ -2041,6 +2069,7 @@ new_owner: T::CrossAccountId, ) -> DispatchResult { let collection_id = collection.id; + collection.consume_sload()?; let full_item = >::get(collection_id, item_id) .ok_or(Error::::TokenNotFound)?; @@ -2053,15 +2082,19 @@ ensure!(amount >= value, Error::::TokenValueTooLow); + collection.consume_sload()?; // update balance let balance_old_owner = >::get(collection_id, item.owner.as_sub()) .checked_sub(value) .ok_or(Error::::NumOverflow)?; + collection.consume_sstore()?; >::insert(collection_id, item.owner.as_sub(), balance_old_owner); + collection.consume_sload()?; let balance_new_owner = >::get(collection_id, new_owner.as_sub()) .checked_add(value) .ok_or(Error::::NumOverflow)?; + collection.consume_sstore()?; >::insert(collection_id, new_owner.as_sub(), balance_new_owner); let old_owner = item.owner.clone(); @@ -2078,10 +2111,11 @@ .find(|i| i.owner == owner) .expect("old owner does present in refungible") .owner = new_owner.clone(); + collection.consume_sstore()?; >::insert(collection_id, item_id, new_full_item); // update index collection - Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?; + Self::move_token_index(collection, item_id, &old_owner, &new_owner)?; } else { new_full_item .owner @@ -2105,9 +2139,10 @@ owner: new_owner.clone(), fraction: value, }); - Self::add_token_index(collection_id, item_id, &new_owner)?; + Self::add_token_index(collection, item_id, &new_owner)?; } + collection.consume_sstore()?; >::insert(collection_id, item_id, new_full_item); } @@ -2129,29 +2164,35 @@ new_owner: T::CrossAccountId, ) -> DispatchResult { let collection_id = collection.id; + collection.consume_sload()?; let mut item = >::get(collection_id, item_id).ok_or(Error::::TokenNotFound)?; ensure!(sender == item.owner, Error::::MustBeTokenOwner); + collection.consume_sload()?; // update balance let balance_old_owner = >::get(collection_id, item.owner.as_sub()) .checked_sub(1) .ok_or(Error::::NumOverflow)?; + collection.consume_sstore()?; >::insert(collection_id, item.owner.as_sub(), balance_old_owner); + collection.consume_sload()?; let balance_new_owner = >::get(collection_id, new_owner.as_sub()) .checked_add(1) .ok_or(Error::::NumOverflow)?; + collection.consume_sstore()?; >::insert(collection_id, new_owner.as_sub(), balance_new_owner); // change owner let old_owner = item.owner.clone(); item.owner = new_owner.clone(); + collection.consume_sstore()?; >::insert(collection_id, item_id, item); // update index collection - Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?; + Self::move_token_index(collection, item_id, &old_owner, &new_owner)?; collection.log(ERC721Events::Transfer { from: *sender.as_eth(), @@ -2231,7 +2272,12 @@ fn init_nft_token(collection_id: CollectionId, item: &NftItemType) { let current_index = ::get(collection_id).checked_add(1).unwrap(); - Self::add_token_index(collection_id, current_index, &item.owner).unwrap(); + Self::add_token_index( + &CollectionHandle::get(collection_id).unwrap(), + current_index, + &item.owner, + ) + .unwrap(); ::insert(collection_id, current_index); @@ -2250,7 +2296,12 @@ ) { let current_index = ::get(collection_id).checked_add(1).unwrap(); - Self::add_token_index(collection_id, current_index, owner).unwrap(); + Self::add_token_index( + &CollectionHandle::get(collection_id).unwrap(), + current_index, + owner, + ) + .unwrap(); ::insert(collection_id, current_index); @@ -2271,7 +2322,12 @@ let value = item.owner.first().unwrap().fraction; let owner = item.owner.first().unwrap().owner.clone(); - Self::add_token_index(collection_id, current_index, &owner).unwrap(); + Self::add_token_index( + &CollectionHandle::get(collection_id).unwrap(), + current_index, + &owner, + ) + .unwrap(); ::insert(collection_id, current_index); @@ -2283,51 +2339,61 @@ } fn add_token_index( - collection_id: CollectionId, + collection: &CollectionHandle, item_index: TokenId, owner: &T::CrossAccountId, ) -> DispatchResult { // add to account limit + collection.consume_sload()?; if >::contains_key(owner.as_sub()) { // bound Owned tokens by a single address + collection.consume_sload()?; let count = >::get(owner.as_sub()); ensure!( count < ChainLimit::get().account_token_ownership_limit, Error::::AddressOwnershipLimitExceeded ); + collection.consume_sstore()?; >::insert( owner.as_sub(), count.checked_add(1).ok_or(Error::::NumOverflow)?, ); } else { + collection.consume_sstore()?; >::insert(owner.as_sub(), 1); } - let list_exists = >::contains_key(collection_id, owner.as_sub()); + collection.consume_sload()?; + let list_exists = >::contains_key(collection.id, owner.as_sub()); if list_exists { - let mut list = >::get(collection_id, owner.as_sub()); + collection.consume_sload()?; + let mut list = >::get(collection.id, owner.as_sub()); let item_contains = list.contains(&item_index.clone()); if !item_contains { list.push(item_index); } - >::insert(collection_id, owner.as_sub(), list); + collection.consume_sstore()?; + >::insert(collection.id, owner.as_sub(), list); } else { let itm = vec![item_index]; - >::insert(collection_id, owner.as_sub(), itm); + collection.consume_sstore()?; + >::insert(collection.id, owner.as_sub(), itm); } Ok(()) } fn remove_token_index( - collection_id: CollectionId, + collection: &CollectionHandle, item_index: TokenId, owner: &T::CrossAccountId, ) -> DispatchResult { // update counter + collection.consume_sload()?; + collection.consume_sstore()?; >::insert( owner.as_sub(), >::get(owner.as_sub()) @@ -2335,14 +2401,17 @@ .ok_or(Error::::NumOverflow)?, ); - let list_exists = >::contains_key(collection_id, owner.as_sub()); + collection.consume_sload()?; + let list_exists = >::contains_key(collection.id, owner.as_sub()); if list_exists { - let mut list = >::get(collection_id, owner.as_sub()); + collection.consume_sload()?; + let mut list = >::get(collection.id, owner.as_sub()); let item_contains = list.contains(&item_index.clone()); if item_contains { list.retain(|&item| item != item_index); - >::insert(collection_id, owner.as_sub(), list); + collection.consume_sstore()?; + >::insert(collection.id, owner.as_sub(), list); } } @@ -2350,13 +2419,13 @@ } fn move_token_index( - collection_id: CollectionId, + collection: &CollectionHandle, item_index: TokenId, old_owner: &T::CrossAccountId, new_owner: &T::CrossAccountId, ) -> DispatchResult { - Self::remove_token_index(collection_id, item_index, old_owner)?; - Self::add_token_index(collection_id, item_index, new_owner)?; + Self::remove_token_index(collection, item_index, old_owner)?; + Self::add_token_index(collection, item_index, new_owner)?; Ok(()) }