--- a/pallets/balances-adapter/src/common.rs +++ b/pallets/balances-adapter/src/common.rs @@ -7,6 +7,8 @@ use up_data_structs::TokenId; pub struct CommonWeights(PhantomData); + +// All implementations with `Weight::default` used in methods that return error `UnsupportedOperation`. impl CommonWeightInfo for CommonWeights { fn create_multiple_items(_amount: &[up_data_structs::CreateItemData]) -> Weight { Weight::default() --- a/pallets/balances-adapter/src/erc.rs +++ b/pallets/balances-adapter/src/erc.rs @@ -1,9 +1,8 @@ use crate::{Config, NativeFungibleHandle, Pallet, SelfWeightOf}; -use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*}; -use frame_support::traits::{Currency, ExistenceRequirement}; +use evm_coder::{abi::AbiType, generate_stubgen, solidity_interface, types::*}; +use frame_support::traits::{Currency}; use pallet_balances::WeightInfo; use pallet_common::{ - consume_store_reads, erc::{CommonEvmHandler, CrossAccountId, PrecompileHandle, PrecompileResult}, eth::CrossAddress, }; @@ -14,38 +13,24 @@ }; use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _}; use sp_core::{U256, Get}; -use sp_std::vec::Vec; frontier_contract! { macro_rules! NativeFungibleHandle_result {...} impl Contract for NativeFungibleHandle {...} } -#[derive(ToLog)] -pub enum ERC20Events { - Transfer { - #[indexed] - from: Address, - #[indexed] - to: Address, - value: U256, - }, -} - -#[solidity_interface(name = ERC20, events(ERC20Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)] +#[solidity_interface(name = ERC20, enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)] impl NativeFungibleHandle { fn allowance(&self, _owner: Address, _spender: Address) -> Result { Ok(U256::zero()) } - // #[weight(>::approve())] fn approve(&mut self, _caller: Caller, _spender: Address, _amount: U256) -> Result { - // self.consume_store_reads(1)?; Err("Approve not supported".into()) } fn balance_of(&self, owner: Address) -> Result { - consume_store_reads(self, 1)?; + self.consume_store_reads(1)?; let owner = T::CrossAccountId::from_eth(owner); let balance = ::Currency::free_balance(owner.as_sub()); Ok(balance.into()) @@ -64,7 +49,7 @@ } fn total_supply(&self) -> Result { - consume_store_reads(self, 1)?; + self.consume_store_reads(1)?; let total = ::Currency::total_issuance(); Ok(total.into()) } @@ -111,7 +96,7 @@ T::AccountId: From<[u8; 32]>, { fn balance_of_cross(&self, owner: CrossAddress) -> Result { - consume_store_reads(self, 1)?; + self.consume_store_reads(1)?; let owner = owner.into_sub_cross_account::()?; let balance = ::Currency::free_balance(owner.as_sub()); Ok(balance.into()) @@ -122,18 +107,13 @@ let caller = T::CrossAccountId::from_eth(caller); let to = to.into_sub_cross_account::()?; let amount = amount.try_into().map_err(|_| "amount overflow")?; - // let budget = self - // .recorder - // .weight_calls_budget(>::find_parent()); + let budget = self + .recorder() + .weight_calls_budget(>::find_parent()); + + >::transfer(self, &caller, &to, amount, &budget) + .map_err(|e| dispatch_to_evm::(e.error))?; - // >::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?; - ::Currency::transfer( - caller.as_sub(), - to.as_sub(), - amount, - ExistenceRequirement::KeepAlive, - ) - .map_err(dispatch_to_evm::)?; Ok(true) } @@ -154,19 +134,13 @@ return Err("no permission".into()); } - // let budget = self - // .recorder - // .weight_calls_budget(>::find_parent()); + let budget = self + .recorder() + .weight_calls_budget(>::find_parent()); + + >::transfer_from(self, &caller, &from, &to, amount, &budget) + .map_err(|e| dispatch_to_evm::(e.error))?; - // >::transfer_from(self, &caller, &from, &to, amount, &budget) - // .map_err(dispatch_to_evm::)?; - ::Currency::transfer( - caller.as_sub(), - to.as_sub(), - amount, - ExistenceRequirement::KeepAlive, - ) - .map_err(dispatch_to_evm::)?; Ok(true) } } --- a/pallets/balances-adapter/src/lib.rs +++ b/pallets/balances-adapter/src/lib.rs @@ -1,4 +1,3 @@ -// #![doc = include_str!("../README.md")] #![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; @@ -12,9 +11,6 @@ pub mod erc; pub(crate) type SelfWeightOf = ::WeightInfo; - -const NATIVE_FUNGIBLE_COLLECTION_ID: up_data_structs::CollectionId = - up_data_structs::CollectionId(0); /// Handle for native fungible collection pub struct NativeFungibleHandle(SubstrateRecorder); @@ -57,7 +53,10 @@ traits::{Currency, ExistenceRequirement, Get}, }; use pallet_balances::WeightInfo; - use pallet_common::{erc::CrossAccountId, Error as CommonError, Pallet as PalletCommon}; + use pallet_common::{ + erc::CrossAccountId, Error as CommonError, Pallet as PalletCommon, + NATIVE_FUNGIBLE_COLLECTION_ID, + }; use pallet_structure::Pallet as PalletStructure; use sp_core::U256; use sp_runtime::DispatchError; @@ -95,10 +94,9 @@ /// Checks if a non-owner has (enough) allowance from the owner to perform operations on the tokens. /// Returns the expected remaining allowance - it should be set manually if the transaction proceeds. /// - /// - `collection`: Collection that contains the token. /// - `spender`: CrossAccountId who has the allowance rights. /// - `from`: The owner of the tokens who sets the allowance. - /// - `amount`: Amount of tokens by which the allowance sholud be reduced. + /// - `nesting_budget`: Limit for searching parents in-depth to check ownership. fn check_allowed( spender: &T::CrossAccountId, from: &T::CrossAccountId, @@ -127,10 +125,11 @@ /// Transfers the specified amount of tokens. Will check that /// the transfer is allowed for the token. /// + /// - `collection`: Collection that contains the token. /// - `from`: Owner of tokens to transfer. /// - `to`: Recepient of transfered tokens. /// - `amount`: Amount of tokens to transfer. - /// - `collection`: Collection that contains the token + /// - `nesting_budget`: Limit for searching parents in-depth to check ownership. pub fn transfer( _collection: &NativeFungibleHandle, from: &T::CrossAccountId, @@ -147,7 +146,7 @@ amount .try_into() .map_err(|_| sp_runtime::ArithmeticError::Overflow)?, - ExistenceRequirement::KeepAlive, + ExistenceRequirement::AllowDeath, )?; >::nest_if_sent_to_token( @@ -175,6 +174,17 @@ }) } + /// Transfer NFT token from one account to another. + /// + /// Same as the [`Self::transfer`] but spender doesn't needs to be the owner of the token. + /// The owner should set allowance for the spender to transfer token. + /// + /// - `collection`: Collection that contains the token. + /// - `spender`: Account that spend the money. + /// - `from`: Owner of tokens to transfer. + /// - `to`: Recepient of transfered tokens. + /// - `amount`: Amount of tokens to transfer. + /// - `nesting_budget`: Limit for searching parents in-depth to check ownership. pub fn transfer_from( collection: &NativeFungibleHandle, spender: &T::CrossAccountId, --- a/pallets/common/src/erc.rs +++ b/pallets/common/src/erc.rs @@ -77,14 +77,6 @@ fn call(self, handle: &mut impl PrecompileHandle) -> Option; } -impl CommonEvmHandler for () { - const CODE: &'static [u8] = &[]; - - fn call(self, _handle: &mut impl PrecompileHandle) -> Option { - None - } -} - /// @title A contract that allows you to work with collections. #[solidity_interface(name = Collection, enum(derive(PreDispatch)), enum_attr(weight))] impl CollectionHandle --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -68,7 +68,6 @@ dispatch::Pays, transactional, fail, }; -use pallet_evm::GasWeightMapping; use up_data_structs::{ AccessMode, COLLECTION_NUMBER_LIMIT, Collection, RpcCollection, CollectionFlags, RpcCollectionFlags, CollectionId, CreateItemData, MAX_TOKEN_PREFIX_LENGTH, @@ -101,7 +100,7 @@ /// Collection handle contains information about collection data and id. /// Also provides functionality to count consumed gas. /// -/// CollectionHandle is used as a generic wrapper for collections of all types. +/// CollectionHandle is used as a generic wrapper for collections of all types (except native fungible). /// It allows to perform common operations and queries on any collection type, /// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`]. #[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"] @@ -153,7 +152,7 @@ &self, reads: u64, ) -> pallet_evm_coder_substrate::execution::Result<()> { - consume_store_reads(self.recorder(), reads) + self.recorder().consume_store_reads(reads) } /// Consume gas for writing. @@ -161,7 +160,7 @@ &self, writes: u64, ) -> pallet_evm_coder_substrate::execution::Result<()> { - consume_store_writes(self.recorder(), writes) + self.recorder().consume_store_writes(writes) } /// Consume gas for reading and writing. @@ -170,7 +169,8 @@ reads: u64, writes: u64, ) -> pallet_evm_coder_substrate::execution::Result<()> { - consume_store_reads_and_writes(self.recorder(), reads, writes) + self.recorder() + .consume_store_reads_and_writes(reads, writes) } /// Save collection to storage. @@ -441,7 +441,7 @@ const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); /// Collection id for native fungible collction. - pub const NATIVE_FINGIBLE_COLLECTION_ID: CollectionId = CollectionId(0); + pub const NATIVE_FUNGIBLE_COLLECTION_ID: CollectionId = CollectionId(0); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -2322,48 +2322,4 @@ PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey, } } -} - -/// Consume gas for reading. -pub fn consume_store_reads( - recorder: &SubstrateRecorder, - reads: u64, -) -> pallet_evm_coder_substrate::execution::Result<()> { - recorder.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts( - ::DbWeight::get() - .read - .saturating_mul(reads), - // TODO: measure proof - 0, - ))) -} - -/// Consume gas for writing. -pub fn consume_store_writes( - recorder: &SubstrateRecorder, - writes: u64, -) -> pallet_evm_coder_substrate::execution::Result<()> { - recorder.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts( - ::DbWeight::get() - .write - .saturating_mul(writes), - // TODO: measure proof - 0, - ))) -} - -/// Consume gas for reading and writing. -pub fn consume_store_reads_and_writes( - recorder: &SubstrateRecorder, - reads: u64, - writes: u64, -) -> pallet_evm_coder_substrate::execution::Result<()> { - let weight = ::DbWeight::get(); - let reads = weight.read.saturating_mul(reads); - let writes = weight.read.saturating_mul(writes); - recorder.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts( - reads.saturating_add(writes), - // TODO: measure proof - 0, - ))) } --- a/pallets/evm-coder-substrate/src/lib.rs +++ b/pallets/evm-coder-substrate/src/lib.rs @@ -37,7 +37,7 @@ ExitError, ExitRevert, ExitSucceed, GasWeightMapping, PrecompileFailure, PrecompileOutput, PrecompileResult, PrecompileHandle, }; -use sp_core::H160; +use sp_core::{Get, H160}; // #[cfg(feature = "runtime-benchmarks")] // pub mod benchmarking; pub mod execution; @@ -204,6 +204,40 @@ Err(Error::Error(e)) => Err(e.into()), }) } + + /// Consume gas for reading. + pub fn consume_store_reads(&self, reads: u64) -> execution::Result<()> { + self.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts( + ::DbWeight::get() + .read + .saturating_mul(reads), + // TODO: measure proof + 0, + ))) + } + + /// Consume gas for writing. + pub fn consume_store_writes(&self, writes: u64) -> execution::Result<()> { + self.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts( + ::DbWeight::get() + .write + .saturating_mul(writes), + // TODO: measure proof + 0, + ))) + } + + /// Consume gas for reading and writing. + pub fn consume_store_reads_and_writes(&self, reads: u64, writes: u64) -> execution::Result<()> { + let weight = ::DbWeight::get(); + let reads = weight.read.saturating_mul(reads); + let writes = weight.read.saturating_mul(writes); + self.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_parts( + reads.saturating_add(writes), + // TODO: measure proof + 0, + ))) + } } pub fn dispatch_to_evm(err: DispatchError) -> execution::Error { --- a/pallets/unique/src/lib.rs +++ b/pallets/unique/src/lib.rs @@ -440,7 +440,7 @@ collection_id: CollectionId, address: T::CrossAccountId, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } @@ -471,7 +471,7 @@ collection_id: CollectionId, address: T::CrossAccountId, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } @@ -501,7 +501,7 @@ collection_id: CollectionId, new_owner: T::AccountId, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); @@ -533,7 +533,7 @@ collection_id: CollectionId, new_admin_id: T::CrossAccountId, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); @@ -562,7 +562,7 @@ collection_id: CollectionId, account_id: T::CrossAccountId, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); @@ -590,7 +590,7 @@ collection_id: CollectionId, new_sponsor: T::AccountId, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); @@ -617,7 +617,7 @@ origin: OriginFor, collection_id: CollectionId, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } let sender = ensure_signed(origin)?; @@ -640,7 +640,7 @@ origin: OriginFor, collection_id: CollectionId, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); @@ -920,7 +920,7 @@ collection_id: CollectionId, value: bool, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); @@ -1175,7 +1175,7 @@ collection_id: CollectionId, new_limit: CollectionLimits, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); @@ -1202,7 +1202,7 @@ collection_id: CollectionId, new_permission: CollectionPermissions, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); @@ -1273,7 +1273,7 @@ origin: OriginFor, collection_id: CollectionId, ) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } ensure_root(origin)?; --- a/runtime/common/dispatch.rs +++ b/runtime/common/dispatch.rs @@ -100,12 +100,11 @@ } fn destroy(sender: T::CrossAccountId, collection_id: CollectionId) -> DispatchResult { - if collection_id == pallet_common::NATIVE_FINGIBLE_COLLECTION_ID { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { fail!(>::UnsupportedOperation); } let collection = >::try_get(collection_id)?; - collection.check_is_internal()?; match collection.mode { CollectionMode::ReFungible => { @@ -122,7 +121,7 @@ } fn dispatch(collection_id: CollectionId) -> Result { - if collection_id == CollectionId(0) { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { return Ok(Self::NativeFungible(NativeFungibleHandle::new())); } @@ -188,7 +187,7 @@ } fn call(handle: &mut impl PrecompileHandle) -> Option { if let Some(collection_id) = map_eth_to_id(&handle.code_address()) { - if collection_id == CollectionId(0) { + if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID { >::new().call(handle) } else { let collection = >::new_with_gas_limit(