git.delta.rocks / unique-network / refs/commits / bea0737bb7ad

difftreelog

feat add nesting

Trubnikov Sergey2023-05-05parent: #3293186.patch.diff
in: master

5 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6264,9 +6264,11 @@
  "pallet-evm",
  "pallet-evm-coder-substrate",
  "pallet-evm-transaction-payment",
+ "pallet-structure",
  "parity-scale-codec",
  "scale-info",
  "sp-core",
+ "sp-runtime",
  "sp-std",
  "up-data-structs",
 ]
modifiedpallets/balances-adapter/Cargo.tomldiffbeforeafterboth
--- a/pallets/balances-adapter/Cargo.toml
+++ b/pallets/balances-adapter/Cargo.toml
@@ -9,7 +9,9 @@
 frame-support = { workspace = true }
 frame-system = { workspace = true }
 pallet-balances = { workspace = true }
+pallet-structure = { workspace = true }
 sp-core = { workspace = true }
+sp-runtime = { workspace = true }
 sp-std = { workspace = true }
 
 #Parity
modifiedpallets/balances-adapter/src/common.rsdiffbeforeafterboth
--- a/pallets/balances-adapter/src/common.rs
+++ b/pallets/balances-adapter/src/common.rs
@@ -1,13 +1,9 @@
 use alloc::{vec, vec::Vec};
 use core::marker::PhantomData;
-use crate::{Config, NativeFungibleHandle};
-use frame_support::{
-	fail,
-	traits::{Currency, ExistenceRequirement},
-	weights::Weight,
-};
+use crate::{Config, NativeFungibleHandle, Pallet};
+use frame_support::{fail, traits::Currency, weights::Weight};
 use pallet_balances::{weights::SubstrateWeight as BalancesWeight, WeightInfo};
-use pallet_common::{erc::CrossAccountId, CommonCollectionOperations, CommonWeightInfo, with_weight};
+use pallet_common::{erc::CrossAccountId, CommonCollectionOperations, CommonWeightInfo};
 use up_data_structs::TokenId;
 
 pub struct CommonWeights<T: Config>(PhantomData<T>);
@@ -188,17 +184,9 @@
 		to: <T>::CrossAccountId,
 		_token: TokenId,
 		amount: u128,
-		_budget: &dyn up_data_structs::budget::Budget,
+		budget: &dyn up_data_structs::budget::Budget,
 	) -> frame_support::pallet_prelude::DispatchResultWithPostInfo {
-		with_weight(
-			<T as Config>::Currency::transfer(
-				sender.as_sub(),
-				to.as_sub(),
-				amount.into(),
-				ExistenceRequirement::KeepAlive,
-			),
-			Default::default(),
-		)
+		<Pallet<T>>::transfer(self, &sender, &to, amount, budget)
 	}
 
 	fn approve(
@@ -229,20 +217,9 @@
 		to: <T>::CrossAccountId,
 		_token: TokenId,
 		amount: u128,
-		_budget: &dyn up_data_structs::budget::Budget,
+		budget: &dyn up_data_structs::budget::Budget,
 	) -> frame_support::pallet_prelude::DispatchResultWithPostInfo {
-		if sender != from {
-			fail!(<pallet_common::Error<T>>::NoPermission);
-		}
-		with_weight(
-			<T as Config>::Currency::transfer(
-				from.as_sub(),
-				to.as_sub(),
-				amount.into(),
-				ExistenceRequirement::KeepAlive,
-			),
-			Default::default(),
-		)
+		<Pallet<T>>::transfer_from(self, &sender, &from, &to, amount, budget)
 	}
 
 	fn burn_from(
modifiedpallets/balances-adapter/src/erc.rsdiffbeforeafterboth
before · pallets/balances-adapter/src/erc.rs
1use crate::{Config, NativeFungibleHandle, SelfWeightOf};2use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};3use frame_support::traits::{Currency, ExistenceRequirement};4use pallet_balances::WeightInfo;5use pallet_common::{6	consume_store_reads,7	erc::{CommonEvmHandler, CrossAccountId, PrecompileHandle, PrecompileResult},8	eth::CrossAddress,9};10use pallet_evm_coder_substrate::{11	call, dispatch_to_evm,12	execution::{PreDispatch, Result},13	frontier_contract,14};15use sp_core::{U256, Get};16use sp_std::vec::Vec;1718frontier_contract! {19	macro_rules! NativeFungibleHandle_result {...}20	impl<T: Config> Contract for NativeFungibleHandle<T> {...}21}2223#[derive(ToLog)]24pub enum ERC20Events {25	Transfer {26		#[indexed]27		from: Address,28		#[indexed]29		to: Address,30		value: U256,31	},32}3334#[solidity_interface(name = ERC20, events(ERC20Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)]35impl<T: Config> NativeFungibleHandle<T> {36	fn allowance(&self, _owner: Address, _spender: Address) -> Result<U256> {37		Ok(U256::zero())38	}3940	// #[weight(<SelfWeightOf<T>>::approve())]41	fn approve(&mut self, _caller: Caller, _spender: Address, _amount: U256) -> Result<bool> {42		// self.consume_store_reads(1)?;43		Err("Approve not supported".into())44	}4546	fn balance_of(&self, owner: Address) -> Result<U256> {47		consume_store_reads(self, 1)?;48		let owner = T::CrossAccountId::from_eth(owner);49		let balance = <T as Config>::Currency::free_balance(owner.as_sub());50		Ok(balance.into())51	}5253	fn decimals(&self) -> Result<u8> {54		Ok(T::Decimals::get())55	}5657	fn name(&self) -> Result<String> {58		Ok(T::Name::get())59	}6061	fn symbol(&self) -> Result<String> {62		Ok(T::Symbol::get())63	}6465	fn total_supply(&self) -> Result<U256> {66		consume_store_reads(self, 1)?;67		let total = <T as Config>::Currency::total_issuance();68		Ok(total.into())69	}7071	#[weight(<SelfWeightOf<T>>::transfer())]72	fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {73		let caller = T::CrossAccountId::from_eth(caller);74		let to = T::CrossAccountId::from_eth(to);75		let amount = amount.try_into().map_err(|_| "amount overflow")?;76		// let budget = self77		// 	.recorder78		// 	.weight_calls_budget(<StructureWeight<T>>::find_parent());7980		// <Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;81		<T as Config>::Currency::transfer(82			caller.as_sub(),83			to.as_sub(),84			amount,85			ExistenceRequirement::KeepAlive,86		)87		.map_err(dispatch_to_evm::<T>)?;88		Ok(true)89	}9091	#[weight(<SelfWeightOf<T>>::transfer())]92	fn transfer_from(93		&mut self,94		caller: Caller,95		from: Address,96		to: Address,97		amount: U256,98	) -> Result<bool> {99		let caller = T::CrossAccountId::from_eth(caller);100		let from = T::CrossAccountId::from_eth(from);101		let to = T::CrossAccountId::from_eth(to);102		let amount = amount.try_into().map_err(|_| "amount overflow")?;103104		if from != caller {105			return Err("no permission".into());106		}107		// let budget = self108		// 	.recorder109		// 	.weight_calls_budget(<StructureWeight<T>>::find_parent());110111		// <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)112		// 	.map_err(dispatch_to_evm::<T>)?;113		<T as Config>::Currency::transfer(114			caller.as_sub(),115			to.as_sub(),116			amount,117			ExistenceRequirement::KeepAlive,118		)119		.map_err(dispatch_to_evm::<T>)?;120		Ok(true)121	}122}123124#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]125impl<T: Config> NativeFungibleHandle<T>126where127	T::AccountId: From<[u8; 32]>,128{129	fn balance_of_cross(&self, owner: CrossAddress) -> Result<U256> {130		consume_store_reads(self, 1)?;131		let owner = owner.into_sub_cross_account::<T>()?;132		let balance = <T as Config>::Currency::free_balance(owner.as_sub());133		Ok(balance.into())134	}135136	#[weight(<SelfWeightOf<T>>::transfer())]137	fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {138		let caller = T::CrossAccountId::from_eth(caller);139		let to = to.into_sub_cross_account::<T>()?;140		let amount = amount.try_into().map_err(|_| "amount overflow")?;141		// let budget = self142		// 	.recorder143		// 	.weight_calls_budget(<StructureWeight<T>>::find_parent());144145		// <Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;146		<T as Config>::Currency::transfer(147			caller.as_sub(),148			to.as_sub(),149			amount,150			ExistenceRequirement::KeepAlive,151		)152		.map_err(dispatch_to_evm::<T>)?;153		Ok(true)154	}155156	#[weight(<SelfWeightOf<T>>::transfer())]157	fn transfer_from_cross(158		&mut self,159		caller: Caller,160		from: CrossAddress,161		to: CrossAddress,162		amount: U256,163	) -> Result<bool> {164		let caller = T::CrossAccountId::from_eth(caller);165		let from = from.into_sub_cross_account::<T>()?;166		let to = to.into_sub_cross_account::<T>()?;167		let amount = amount.try_into().map_err(|_| "amount overflow")?;168169		if from != caller {170			return Err("no permission".into());171		}172173		// let budget = self174		// 	.recorder175		// 	.weight_calls_budget(<StructureWeight<T>>::find_parent());176177		// <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)178		// 	.map_err(dispatch_to_evm::<T>)?;179		<T as Config>::Currency::transfer(180			caller.as_sub(),181			to.as_sub(),182			amount,183			ExistenceRequirement::KeepAlive,184		)185		.map_err(dispatch_to_evm::<T>)?;186		Ok(true)187	}188}189190#[solidity_interface(191	name = UniqueNativeFungible,192	is(ERC20, ERC20UniqueExtensions),193	enum(derive(PreDispatch))194)]195impl<T: Config> NativeFungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}196197generate_stubgen!(gen_impl, UniqueNativeFungibleCall<()>, true);198generate_stubgen!(gen_iface, UniqueNativeFungibleCall<()>, false);199200impl<T: Config> CommonEvmHandler for NativeFungibleHandle<T>201where202	T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,203{204	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNativeFungible.raw");205206	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {207		call::<T, UniqueNativeFungibleCall<T>, _, _>(handle, self)208	}209}
modifiedpallets/balances-adapter/src/lib.rsdiffbeforeafterboth
--- a/pallets/balances-adapter/src/lib.rs
+++ b/pallets/balances-adapter/src/lib.rs
@@ -5,14 +5,17 @@
 use core::ops::Deref;
 
 use frame_support::sp_runtime::DispatchResult;
+use pallet_evm_coder_substrate::{WithRecorder, SubstrateRecorder};
 pub use pallet::*;
-use pallet_evm_coder_substrate::{WithRecorder, SubstrateRecorder};
 
 pub mod common;
 pub mod erc;
 
 pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
 
+const NATIVE_FUNGIBLE_COLLECTION_ID: up_data_structs::CollectionId =
+	up_data_structs::CollectionId(0);
+
 /// Handle for native fungible collection
 pub struct NativeFungibleHandle<T: Config>(SubstrateRecorder<T>);
 impl<T: Config> NativeFungibleHandle<T> {
@@ -45,14 +48,27 @@
 }
 #[frame_support::pallet]
 pub mod pallet {
+	use super::*;
 	use alloc::string::String;
-	use frame_support::{traits::Get};
+	use frame_support::{
+		dispatch::PostDispatchInfo,
+		ensure,
+		pallet_prelude::{DispatchResultWithPostInfo, Pays},
+		traits::{Currency, ExistenceRequirement, Get},
+	};
 	use pallet_balances::WeightInfo;
+	use pallet_common::{erc::CrossAccountId, Error as CommonError, Pallet as PalletCommon};
+	use pallet_structure::Pallet as PalletStructure;
 	use sp_core::U256;
+	use sp_runtime::DispatchError;
+	use up_data_structs::{budget::Budget, mapping::TokenAddressMapping, TokenId};
 
 	#[pallet::config]
 	pub trait Config:
-		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_common::Config
+		frame_system::Config
+		+ pallet_evm_coder_substrate::Config
+		+ pallet_common::Config
+		+ pallet_structure::Config
 	{
 		/// Currency from `pallet_balances`
 		type Currency: frame_support::traits::Currency<
@@ -74,4 +90,104 @@
 	}
 	#[pallet::pallet]
 	pub struct Pallet<T>(_);
+
+	impl<T: Config> Pallet<T> {
+		/// 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.
+		fn check_allowed(
+			spender: &T::CrossAccountId,
+			from: &T::CrossAccountId,
+			nesting_budget: &dyn Budget,
+		) -> Result<u128, DispatchError> {
+			if spender.conv_eq(from) {
+				return Ok(0);
+			}
+
+			if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {
+				ensure!(
+					<PalletStructure<T>>::check_indirectly_owned(
+						spender.clone(),
+						source.0,
+						source.1,
+						None,
+						nesting_budget
+					)?,
+					<CommonError<T>>::ApprovedValueTooLow,
+				);
+			} else if spender != from {
+				return Ok(0);
+			}
+
+			Ok(<T as Config>::Currency::free_balance(from.as_sub()).into())
+		}
+
+		/// Transfers the specified amount of tokens. Will check that
+		/// the transfer is allowed for 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
+		pub fn transfer(
+			_collection: &NativeFungibleHandle<T>,
+			from: &T::CrossAccountId,
+			to: &T::CrossAccountId,
+			amount: u128,
+			nesting_budget: &dyn Budget,
+		) -> DispatchResultWithPostInfo {
+			<PalletCommon<T>>::ensure_correct_receiver(to)?;
+
+			if from != to && amount != 0 {
+				<T as Config>::Currency::transfer(
+					from.as_sub(),
+					to.as_sub(),
+					amount.into(),
+					ExistenceRequirement::KeepAlive,
+				)?;
+
+				<PalletStructure<T>>::nest_if_sent_to_token(
+					from.clone(),
+					to,
+					NATIVE_FUNGIBLE_COLLECTION_ID,
+					TokenId::default(),
+					nesting_budget,
+				)?;
+
+				let balance_from: u128 =
+					<T as Config>::Currency::free_balance(from.as_sub()).into();
+				if balance_from == 0 {
+					<PalletStructure<T>>::unnest_if_nested(
+						from,
+						NATIVE_FUNGIBLE_COLLECTION_ID,
+						TokenId::default(),
+					);
+				}
+			};
+
+			Ok(PostDispatchInfo {
+				actual_weight: Some(<SelfWeightOf<T>>::transfer()),
+				pays_fee: Pays::Yes,
+			})
+		}
+
+		pub fn transfer_from(
+			collection: &NativeFungibleHandle<T>,
+			spender: &T::CrossAccountId,
+			from: &T::CrossAccountId,
+			to: &T::CrossAccountId,
+			amount: u128,
+			nesting_budget: &dyn Budget,
+		) -> DispatchResultWithPostInfo {
+			let allowance = Self::check_allowed(collection, spender, from, amount, nesting_budget)?;
+			if allowance < amount {
+				return Err(<CommonError<T>>::ApprovedValueTooLow.into());
+			}
+			Self::transfer(collection, from, to, amount, nesting_budget)
+		}
+	}
 }