git.delta.rocks / unique-network / refs/commits / 5fc39c3d8a70

difftreelog

refactor rewrite nft pallet to evm helpers

Yaroslav Bolyukin2021-07-27parent: #b905ada.patch.diff
in: master

7 files changed

modifiedpallets/nft/Cargo.tomldiffbeforeafterboth
--- a/pallets/nft/Cargo.toml
+++ b/pallets/nft/Cargo.toml
@@ -39,7 +39,7 @@
 
     'primitive-types/std',
     'evm-coder/std',
-    'evm-coder-substrate/std',
+    'pallet-evm-coder-substrate/std',
 ]
 
 ################################################################################
@@ -144,10 +144,12 @@
 sp-api = { default-features = false, version = '3.0.0', git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.8" }
 
 evm-coder = { default-features = false, path = "../../crates/evm-coder" }
-evm-coder-substrate = { default-features = false, path = "../../crates/evm-coder-substrate" }
-primitive-types = { version = "0.9.0", default-features = false, features = ["serde_no_std"] }
+pallet-evm-coder-substrate = { default-features = false, path = "../../pallets/evm-coder-substrate" }
+primitive-types = { version = "0.9.0", default-features = false, features = [
+    "serde_no_std",
+] }
 
 pallet-evm = { default-features = false, version = "5.0.0-dev", git = "https://github.com/uniquenetwork/frontier.git", branch = "injected-transactions-parachain" }
 pallet-ethereum = { default-features = false, version = "3.0.0-dev", git = "https://github.com/uniquenetwork/frontier.git", branch = "injected-transactions-parachain" }
 fp-evm = { default-features = false, version = '2.0.0', git = "https://github.com/uniquenetwork/frontier.git", branch = "injected-transactions-parachain" }
-hex-literal = "0.3.1"
\ No newline at end of file
+hex-literal = "0.3.1"
modifiedpallets/nft/src/eth/erc.rsdiffbeforeafterboth
--- a/pallets/nft/src/eth/erc.rs
+++ b/pallets/nft/src/eth/erc.rs
@@ -1,46 +1,63 @@
-use evm_coder::{solidity_interface, solidity, types::*, ToLog};
+use core::char::{decode_utf16, REPLACEMENT_CHARACTER};
+use evm_coder::{ToLog, execution::Result, solidity, solidity_interface, types::*};
+use core::convert::TryInto;
+use alloc::format;
+use crate::{Allowances, Module, Balance, CollectionHandle, CollectionMode, Config, NftItemList};
+use frame_support::storage::StorageDoubleMap;
+use pallet_evm::AddressMapping;
+use super::account::CrossAccountId;
 use sp_std::vec::Vec;
 
-#[solidity_interface]
-pub trait InlineNameSymbol {
-	type Error;
-
-	fn name(&self) -> Result<string, Self::Error>;
-	fn symbol(&self) -> Result<string, Self::Error>;
+#[solidity_interface(name = "ERC165")]
+impl<T: Config> CollectionHandle<T> {
+	fn supports_interface(&self, interface_id: bytes4) -> Result<bool> {
+		Ok(match self.mode {
+			CollectionMode::Fungible(_) => UniqueFungibleCall::supports_interface(interface_id),
+			CollectionMode::NFT => UniqueNFTCall::supports_interface(interface_id),
+			_ => false,
+		})
+	}
 }
 
-#[solidity_interface]
-pub trait InlineTotalSupply {
-	type Error;
+#[solidity_interface(name = "InlineNameSymbol")]
+impl<T: Config> CollectionHandle<T> {
+	fn name(&self) -> Result<string> {
+		Ok(decode_utf16(self.name.iter().copied())
+			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
+			.collect::<string>())
+	}
 
-	fn total_supply(&self) -> Result<uint256, Self::Error>;
+	fn symbol(&self) -> Result<string> {
+		Ok(string::from_utf8_lossy(&self.token_prefix).into())
+	}
 }
 
-#[solidity_interface]
-pub trait ERC165 {
-	type Error;
-
-	fn supports_interface(&self, interface_id: bytes4) -> Result<bool, Self::Error>;
+#[solidity_interface(name = "InlineTotalSupply")]
+impl<T: Config> CollectionHandle<T> {
+	fn total_supply(&self) -> Result<uint256> {
+		// TODO: we do not track total amount of all tokens
+		Ok(0.into())
+	}
 }
 
-#[solidity_interface(inline_is(InlineNameSymbol))]
-pub trait ERC721Metadata {
-	type Error;
-
-	#[solidity(rename_selector = "tokenURI")]
-	fn token_uri(&self, token_id: uint256) -> Result<string, Self::Error>;
+#[solidity_interface(name = "ERC721Metadata", inline_is(InlineNameSymbol))]
+impl<T: Config> CollectionHandle<T> {
+	fn token_uri(&self, token_id: uint256) -> Result<string> {
+		// TODO: We should standartize url prefix, maybe via offchain schema?
+		Ok(format!("unique.network/{}/{}", self.id, token_id))
+	}
 }
 
-#[solidity_interface(inline_is(InlineTotalSupply))]
-pub trait ERC721Enumerable {
-	type Error;
+#[solidity_interface(name = "ERC721Enumerable", inline_is(InlineTotalSupply))]
+impl<T: Config> CollectionHandle<T> {
+	fn token_by_index(&self, index: uint256) -> Result<uint256> {
+		Ok(index)
+	}
 
-	fn token_by_index(&self, index: uint256) -> Result<uint256, Self::Error>;
-	fn token_of_owner_by_index(
-		&self,
-		owner: address,
-		index: uint256,
-	) -> Result<uint256, Self::Error>;
+	fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {
+		// TODO: Not implemetable
+		Err("not implemented".into())
+	}
 }
 
 #[derive(ToLog)]
@@ -71,29 +88,40 @@
 	},
 }
 
-#[solidity_interface(is(ERC165), events(ERC721Events))]
-pub trait ERC721 {
-	type Error;
-
-	fn balance_of(&self, owner: address) -> Result<uint256, Self::Error>;
-	fn owner_of(&self, token_id: uint256) -> Result<address, Self::Error>;
-
-	#[solidity(rename_selector = "safeTransferFrom")]
+#[solidity_interface(name = "ERC721", is(ERC165), events(ERC721Events))]
+impl<T: Config> CollectionHandle<T> {
+	#[solidity(rename_selector = "balanceOf")]
+	fn balance_of_nft(&self, owner: address) -> Result<uint256> {
+		let owner = T::EvmAddressMapping::into_account_id(owner);
+		let balance = <Balance<T>>::get(self.id, owner);
+		Ok(balance.into())
+	}
+	fn owner_of(&self, token_id: uint256) -> Result<address> {
+		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
+		let token = <NftItemList<T>>::get(self.id, token_id).ok_or("unknown token")?;
+		Ok(*token.owner.as_eth())
+	}
 	fn safe_transfer_from_with_data(
 		&mut self,
-		from: address,
-		to: address,
-		token_id: uint256,
-		data: bytes,
-		value: value,
-	) -> Result<void, Self::Error>;
+		_from: address,
+		_to: address,
+		_token_id: uint256,
+		_data: bytes,
+		_value: value,
+	) -> Result<void> {
+		// TODO: Not implemetable
+		Err("not implemented".into())
+	}
 	fn safe_transfer_from(
 		&mut self,
-		from: address,
-		to: address,
-		token_id: uint256,
-		value: value,
-	) -> Result<void, Self::Error>;
+		_from: address,
+		_to: address,
+		_token_id: uint256,
+		_value: value,
+	) -> Result<void> {
+		// TODO: Not implemetable
+		Err("not implemented".into())
+	}
 
 	fn transfer_from(
 		&mut self,
@@ -101,53 +129,86 @@
 		from: address,
 		to: address,
 		token_id: uint256,
-		value: value,
-	) -> Result<void, Self::Error>;
+		_value: value,
+	) -> Result<void> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let from = T::CrossAccountId::from_eth(from);
+		let to = T::CrossAccountId::from_eth(to);
+		let token_id = token_id.try_into().map_err(|_| "token_id overflow")?;
+
+		<Module<T>>::transfer_from_internal(&caller, &from, &to, self, token_id, 1)
+			.map_err(|_| "transferFrom error")?;
+		Ok(())
+	}
+
 	fn approve(
 		&mut self,
 		caller: caller,
 		approved: address,
 		token_id: uint256,
-		value: value,
-	) -> Result<void, Self::Error>;
+		_value: value,
+	) -> Result<void> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let approved = T::CrossAccountId::from_eth(approved);
+		let token_id = token_id.try_into().map_err(|_| "token_id overflow")?;
+
+		<Module<T>>::approve_internal(&caller, &approved, self, token_id, 1)
+			.map_err(|_| "approve internal")?;
+		Ok(())
+	}
+
 	fn set_approval_for_all(
 		&mut self,
-		caller: caller,
-		operator: address,
-		approved: bool,
-	) -> Result<void, Self::Error>;
+		_caller: caller,
+		_operator: address,
+		_approved: bool,
+	) -> Result<void> {
+		// TODO: Not implemetable
+		Err("not implemented".into())
+	}
+
+	fn get_approved(&self, _token_id: uint256) -> Result<address> {
+		// TODO: Not implemetable
+		Err("not implemented".into())
+	}
 
-	fn get_approved(&self, token_id: uint256) -> Result<address, Self::Error>;
-	fn is_approved_for_all(
-		&self,
-		owner: address,
-		operator: address,
-	) -> Result<address, Self::Error>;
+	fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {
+		// TODO: Not implemetable
+		Err("not implemented".into())
+	}
 }
 
-#[solidity_interface]
-pub trait ERC721UniqueExtensions {
-	type Error;
-
-	fn transfer(
+#[solidity_interface(name = "ERC721UniqueExtensions")]
+impl<T: Config> CollectionHandle<T> {
+	#[solidity(rename_selector = "transfer")]
+	fn transfer_nft(
 		&mut self,
 		caller: caller,
 		to: address,
 		token_id: uint256,
-		value: value,
-	) -> Result<void, Self::Error>;
+		_value: value,
+	) -> Result<void> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let to = T::CrossAccountId::from_eth(to);
+		let token_id = token_id.try_into().map_err(|_| "amount overflow")?;
+
+		<Module<T>>::transfer_internal(&caller, &to, self, token_id, 1)
+			.map_err(|_| "transfer error")?;
+		Ok(())
+	}
 }
 
-#[solidity_interface(is(
-	ERC165,
-	ERC721,
-	ERC721Metadata,
-	ERC721Enumerable,
-	ERC721UniqueExtensions
-))]
-pub trait UniqueNFT {
-	type Error;
-}
+#[solidity_interface(
+	name = "UniqueNFT",
+	is(
+		ERC165,
+		ERC721,
+		ERC721Metadata,
+		ERC721Enumerable,
+		ERC721UniqueExtensions
+	)
+)]
+impl<T: Config> CollectionHandle<T> {}
 
 #[derive(ToLog)]
 pub enum ERC20Events {
@@ -167,35 +228,72 @@
 	},
 }
 
-#[solidity_interface(inline_is(InlineNameSymbol, InlineTotalSupply), events(ERC20Events))]
-pub trait ERC20 {
-	type Error;
+#[solidity_interface(
+	name = "ERC20",
+	inline_is(InlineNameSymbol, InlineTotalSupply),
+	events(ERC20Events)
+)]
+impl<T: Config> CollectionHandle<T> {
+	fn decimals(&self) -> Result<uint8> {
+		Ok(if let CollectionMode::Fungible(decimals) = &self.mode {
+			*decimals
+		} else {
+			unreachable!()
+		})
+	}
+	fn balance_of(&self, owner: address) -> Result<uint256> {
+		let owner = T::EvmAddressMapping::into_account_id(owner);
+		let balance = <Balance<T>>::get(self.id, owner);
+		Ok(balance.into())
+	}
+	fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let to = T::CrossAccountId::from_eth(to);
+		let amount = amount.try_into().map_err(|_| "amount overflow")?;
 
-	fn decimals(&self) -> Result<uint8, Self::Error>;
-	fn balance_of(&self, owner: address) -> Result<uint256, Self::Error>;
-	fn transfer(
-		&mut self,
-		caller: caller,
-		to: address,
-		value: uint256,
-	) -> Result<bool, Self::Error>;
-	fn transfer_from(
+		<Module<T>>::transfer_internal(&caller, &to, self, 1, amount)
+			.map_err(|_| "transfer error")?;
+		Ok(true)
+	}
+	#[solidity(rename_selector = "transferFrom")]
+	fn transfer_from_fungible(
 		&mut self,
 		caller: caller,
 		from: address,
 		to: address,
-		value: uint256,
-	) -> Result<bool, Self::Error>;
-	fn approve(
+		amount: uint256,
+	) -> Result<bool> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let from = T::CrossAccountId::from_eth(from);
+		let to = T::CrossAccountId::from_eth(to);
+		let amount = amount.try_into().map_err(|_| "amount overflow")?;
+
+		<Module<T>>::transfer_from_internal(&caller, &from, &to, self, 1, amount)
+			.map_err(|_| "transferFrom error")?;
+		Ok(true)
+	}
+	#[solidity(rename_selector = "approve")]
+	fn approve_fungible(
 		&mut self,
 		caller: caller,
 		spender: address,
-		value: uint256,
-	) -> Result<bool, Self::Error>;
-	fn allowance(&self, owner: address, spender: address) -> Result<uint256, Self::Error>;
-}
+		amount: uint256,
+	) -> Result<bool> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let spender = T::CrossAccountId::from_eth(spender);
+		let amount = amount.try_into().map_err(|_| "amount overflow")?;
+
+		<Module<T>>::approve_internal(&caller, &spender, self, 1, amount)
+			.map_err(|_| "approve internal")?;
+		Ok(true)
+	}
+	fn allowance(&self, owner: address, spender: address) -> Result<uint256> {
+		let owner = T::CrossAccountId::from_eth(owner);
+		let spender = T::CrossAccountId::from_eth(spender);
 
-#[solidity_interface(is(ERC165, ERC20))]
-pub trait UniqueFungible {
-	type Error;
+		Ok(<Allowances<T>>::get(self.id, (1, owner.as_sub(), spender.as_sub())).into())
+	}
 }
+
+#[solidity_interface(name = "UniqueFungible", is(ERC165, ERC20))]
+impl<T: Config> CollectionHandle<T> {}
deletedpallets/nft/src/eth/erc_impl.rsdiffbeforeafterboth
--- a/pallets/nft/src/eth/erc_impl.rs
+++ /dev/null
@@ -1,283 +0,0 @@
-use core::char::{decode_utf16, REPLACEMENT_CHARACTER};
-use evm_coder::{
-	abi::{AbiWriter, StringError},
-	types::*,
-};
-use core::convert::TryInto;
-use alloc::format;
-use crate::{Allowances, Module, Balance, CollectionHandle, CollectionMode, Config, NftItemList};
-use frame_support::storage::StorageDoubleMap;
-use pallet_evm::AddressMapping;
-use super::erc::*;
-use super::account::CrossAccountId;
-
-type Result<T> = core::result::Result<T, StringError>;
-
-impl<T: Config> InlineNameSymbol for CollectionHandle<T> {
-	type Error = StringError;
-
-	fn name(&self) -> Result<string> {
-		Ok(decode_utf16(self.name.iter().copied())
-			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
-			.collect::<string>())
-	}
-
-	fn symbol(&self) -> Result<string> {
-		Ok(string::from_utf8_lossy(&self.token_prefix).into())
-	}
-}
-
-impl<T: Config> InlineTotalSupply for CollectionHandle<T> {
-	type Error = StringError;
-
-	fn total_supply(&self) -> Result<uint256> {
-		// TODO: we do not track total amount of all tokens
-		Ok(0.into())
-	}
-}
-
-impl<T: Config> ERC721Metadata for CollectionHandle<T> {
-	type Error = StringError;
-
-	fn token_uri(&self, token_id: uint256) -> Result<string> {
-		// TODO: We should standartize url prefix, maybe via offchain schema?
-		Ok(format!("unique.network/{}/{}", self.id, token_id))
-	}
-
-	fn call_inline_name_symbol(&mut self, c: Msg<InlineNameSymbolCall>) -> Result<AbiWriter> {
-		<Self as InlineNameSymbol>::call(self, c)
-	}
-}
-
-impl<T: Config> ERC721Enumerable for CollectionHandle<T> {
-	type Error = StringError;
-
-	fn token_by_index(&self, index: uint256) -> Result<uint256> {
-		Ok(index)
-	}
-
-	fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {
-		// TODO: Not implemetable
-		Err("not implemented".into())
-	}
-
-	fn call_inline_total_supply(&mut self, c: Msg<InlineTotalSupplyCall>) -> Result<AbiWriter> {
-		<Self as InlineTotalSupply>::call(self, c)
-	}
-}
-
-impl<T: Config> ERC721 for CollectionHandle<T> {
-	type Error = StringError;
-
-	fn balance_of(&self, owner: address) -> Result<uint256> {
-		let owner = T::EvmAddressMapping::into_account_id(owner);
-		let balance = <Balance<T>>::get(self.id, owner);
-		Ok(balance.into())
-	}
-	fn owner_of(&self, token_id: uint256) -> Result<address> {
-		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
-		let token = <NftItemList<T>>::get(self.id, token_id).ok_or("unknown token")?;
-		Ok(*token.owner.as_eth())
-	}
-	fn safe_transfer_from_with_data(
-		&mut self,
-		_from: address,
-		_to: address,
-		_token_id: uint256,
-		_data: bytes,
-		_value: value,
-	) -> Result<void> {
-		// TODO: Not implemetable
-		Err("not implemented".into())
-	}
-	fn safe_transfer_from(
-		&mut self,
-		_from: address,
-		_to: address,
-		_token_id: uint256,
-		_value: value,
-	) -> Result<void> {
-		// TODO: Not implemetable
-		Err("not implemented".into())
-	}
-
-	fn transfer_from(
-		&mut self,
-		caller: caller,
-		from: address,
-		to: address,
-		token_id: uint256,
-		_value: value,
-	) -> Result<void> {
-		let caller = T::CrossAccountId::from_eth(caller);
-		let from = T::CrossAccountId::from_eth(from);
-		let to = T::CrossAccountId::from_eth(to);
-		let token_id = token_id.try_into().map_err(|_| "token_id overflow")?;
-
-		<Module<T>>::transfer_from_internal(&caller, &from, &to, self, token_id, 1)
-			.map_err(|_| "transferFrom error")?;
-		Ok(())
-	}
-
-	fn approve(
-		&mut self,
-		caller: caller,
-		approved: address,
-		token_id: uint256,
-		_value: value,
-	) -> Result<void> {
-		let caller = T::CrossAccountId::from_eth(caller);
-		let approved = T::CrossAccountId::from_eth(approved);
-		let token_id = token_id.try_into().map_err(|_| "token_id overflow")?;
-
-		<Module<T>>::approve_internal(&caller, &approved, self, token_id, 1)
-			.map_err(|_| "approve internal")?;
-		Ok(())
-	}
-
-	fn set_approval_for_all(
-		&mut self,
-		_caller: caller,
-		_operator: address,
-		_approved: bool,
-	) -> Result<void> {
-		// TODO: Not implemetable
-		Err("not implemented".into())
-	}
-
-	fn get_approved(&self, _token_id: uint256) -> Result<address> {
-		// TODO: Not implemetable
-		Err("not implemented".into())
-	}
-
-	fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {
-		// TODO: Not implemetable
-		Err("not implemented".into())
-	}
-
-	fn call_erc165(&mut self, c: Msg<ERC165Call>) -> Result<AbiWriter> {
-		let ERC165Call::SupportsInterface { interface_id } = c.call;
-		Ok(evm_coder::abi_encode!(bool(
-			&ERC721Call::supports_interface(interface_id)
-		)))
-	}
-}
-
-impl<T: Config> ERC721UniqueExtensions for CollectionHandle<T> {
-	type Error = StringError;
-	fn transfer(
-		&mut self,
-		caller: caller,
-		to: address,
-		token_id: uint256,
-		_value: value,
-	) -> Result<void> {
-		let caller = T::CrossAccountId::from_eth(caller);
-		let to = T::CrossAccountId::from_eth(to);
-		let token_id = token_id.try_into().map_err(|_| "amount overflow")?;
-
-		<Module<T>>::transfer_internal(&caller, &to, self, token_id, 1)
-			.map_err(|_| "transfer error")?;
-		Ok(())
-	}
-}
-
-impl<T: Config> UniqueNFT for CollectionHandle<T> {
-	type Error = StringError;
-	fn call_erc165(&mut self, c: Msg<ERC165Call>) -> Result<AbiWriter> {
-		let ERC165Call::SupportsInterface { interface_id } = c.call;
-		Ok(evm_coder::abi_encode!(bool(
-			&UniqueNFTCall::supports_interface(interface_id)
-		)))
-	}
-	fn call_erc721(&mut self, c: Msg<ERC721Call>) -> Result<AbiWriter> {
-		<Self as ERC721>::call(self, c)
-	}
-	fn call_erc721_metadata(&mut self, c: Msg<ERC721MetadataCall>) -> Result<AbiWriter> {
-		<Self as ERC721Metadata>::call(self, c)
-	}
-	fn call_erc721_enumerable(&mut self, c: Msg<ERC721EnumerableCall>) -> Result<AbiWriter> {
-		<Self as ERC721Enumerable>::call(self, c)
-	}
-	fn call_erc721_unique_extensions(
-		&mut self,
-		c: Msg<ERC721UniqueExtensionsCall>,
-	) -> Result<AbiWriter> {
-		<Self as ERC721UniqueExtensions>::call(self, c)
-	}
-}
-
-impl<T: Config> ERC20 for CollectionHandle<T> {
-	type Error = StringError;
-	fn decimals(&self) -> Result<uint8> {
-		Ok(if let CollectionMode::Fungible(decimals) = &self.mode {
-			*decimals
-		} else {
-			unreachable!()
-		})
-	}
-	fn balance_of(&self, owner: address) -> Result<uint256> {
-		let owner = T::EvmAddressMapping::into_account_id(owner);
-		let balance = <Balance<T>>::get(self.id, owner);
-		Ok(balance.into())
-	}
-	fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {
-		let caller = T::CrossAccountId::from_eth(caller);
-		let to = T::CrossAccountId::from_eth(to);
-		let amount = amount.try_into().map_err(|_| "amount overflow")?;
-
-		<Module<T>>::transfer_internal(&caller, &to, self, 1, amount)
-			.map_err(|_| "transfer error")?;
-		Ok(true)
-	}
-	fn transfer_from(
-		&mut self,
-		caller: caller,
-		from: address,
-		to: address,
-		amount: uint256,
-	) -> Result<bool> {
-		let caller = T::CrossAccountId::from_eth(caller);
-		let from = T::CrossAccountId::from_eth(from);
-		let to = T::CrossAccountId::from_eth(to);
-		let amount = amount.try_into().map_err(|_| "amount overflow")?;
-
-		<Module<T>>::transfer_from_internal(&caller, &from, &to, self, 1, amount)
-			.map_err(|_| "transferFrom error")?;
-		Ok(true)
-	}
-	fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {
-		let caller = T::CrossAccountId::from_eth(caller);
-		let spender = T::CrossAccountId::from_eth(spender);
-		let amount = amount.try_into().map_err(|_| "amount overflow")?;
-
-		<Module<T>>::approve_internal(&caller, &spender, self, 1, amount)
-			.map_err(|_| "approve internal")?;
-		Ok(true)
-	}
-	fn allowance(&self, owner: address, spender: address) -> Result<uint256> {
-		let owner = T::CrossAccountId::from_eth(owner);
-		let spender = T::CrossAccountId::from_eth(spender);
-
-		Ok(<Allowances<T>>::get(self.id, (1, owner.as_sub(), spender.as_sub())).into())
-	}
-	fn call_inline_name_symbol(&mut self, c: Msg<InlineNameSymbolCall>) -> Result<AbiWriter> {
-		<Self as InlineNameSymbol>::call(self, c)
-	}
-	fn call_inline_total_supply(&mut self, c: Msg<InlineTotalSupplyCall>) -> Result<AbiWriter> {
-		<Self as InlineTotalSupply>::call(self, c)
-	}
-}
-
-impl<T: Config> UniqueFungible for CollectionHandle<T> {
-	type Error = StringError;
-	fn call_erc165(&mut self, c: Msg<ERC165Call>) -> Result<AbiWriter> {
-		let ERC165Call::SupportsInterface { interface_id } = c.call;
-		Ok(evm_coder::abi_encode!(bool(
-			&UniqueNFTCall::supports_interface(interface_id)
-		)))
-	}
-	fn call_erc20(&mut self, c: Msg<ERC20Call>) -> Result<AbiWriter> {
-		<Self as ERC20>::call(self, c)
-	}
-}
deletedpallets/nft/src/eth/log.rsdiffbeforeafterboth
--- a/pallets/nft/src/eth/log.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-use sp_std::cell::RefCell;
-use sp_std::vec::Vec;
-
-use ethereum::Log;
-
-#[derive(Default)]
-pub struct LogRecorder(RefCell<Vec<Log>>);
-
-impl LogRecorder {
-	pub fn is_empty(&self) -> bool {
-		self.0.borrow().is_empty()
-	}
-	pub fn log(&self, log: Log) {
-		self.0.borrow_mut().push(log);
-	}
-	pub fn retrieve_logs(self) -> Vec<Log> {
-		self.0.into_inner()
-	}
-}
modifiedpallets/nft/src/eth/mod.rsdiffbeforeafterboth
--- a/pallets/nft/src/eth/mod.rs
+++ b/pallets/nft/src/eth/mod.rs
@@ -1,23 +1,15 @@
 pub mod account;
 pub mod erc;
-mod erc_impl;
-pub mod log;
 pub mod sponsoring;
 
-use evm_coder::abi::AbiWriter;
-use evm_coder::abi::StringError;
-use sp_std::prelude::*;
+use pallet_evm_coder_substrate::call_internal;
 use sp_std::borrow::ToOwned;
 use sp_std::vec::Vec;
-
-use pallet_evm::{PrecompileOutput, ExitReason, ExitRevert, ExitSucceed};
+use pallet_evm::{PrecompileOutput};
 use sp_core::{H160, U256};
 use frame_support::storage::StorageMap;
-
 use crate::{Config, CollectionById, CollectionHandle, CollectionId, CollectionMode};
-
-use erc::{UniqueFungible, UniqueFungibleCall, UniqueNFT, UniqueNFTCall};
-use evm_coder::{types::*, abi::AbiReader};
+use erc::{UniqueFungibleCall, UniqueNFTCall};
 
 pub struct NftErcSupport<T: Config>(core::marker::PhantomData<T>);
 
@@ -42,19 +34,17 @@
 	H160(out)
 }
 
+/*
 fn call_internal<T: Config>(
 	collection: &mut CollectionHandle<T>,
 	caller: caller,
 	method_id: u32,
 	mut input: AbiReader,
 	value: U256,
-) -> Result<Option<AbiWriter>, evm_coder::abi::StringError> {
+) -> Result<Option<AbiWriter>> {
 	match collection.mode.clone() {
 		CollectionMode::Fungible(_) => {
-			#[cfg(feature = "std")]
-			{
-				println!("Parse fungible call {:x}", method_id);
-			}
+			call_internal();
 			let call = match UniqueFungibleCall::parse(method_id, &mut input)? {
 				Some(v) => v,
 				None => {
@@ -65,10 +55,6 @@
 					return Ok(None);
 				}
 			};
-			#[cfg(feature = "std")]
-			{
-				dbg!(&call);
-			}
 			Ok(Some(<CollectionHandle<T> as UniqueFungible>::call(
 				collection,
 				Msg {
@@ -92,11 +78,9 @@
 				},
 			)?))
 		}
-		_ => Err(StringError::from(
-			"erc calls only supported to fungible and nft collections for now",
-		)),
+		_ => Err("erc calls only supported to fungible and nft collections for now".into()),
 	}
-}
+}*/
 
 impl<T: Config> pallet_evm::OnMethodCall<T> for NftErcSupport<T> {
 	fn is_reserved(target: &H160) -> bool {
@@ -129,56 +113,15 @@
 	) -> Option<PrecompileOutput> {
 		let mut collection = map_eth_to_id(target)
 			.and_then(|id| <CollectionHandle<T>>::get_with_gas_limit(id, gas_limit))?;
-		let (method_id, input) = AbiReader::new_call(input).unwrap();
-		let result = call_internal(&mut collection, *source, method_id, input, value);
-		let cost = gas_limit - collection.gas_left();
-		let logs = collection.logs.retrieve_logs();
-		match result {
-			Ok(Some(v)) => Some(PrecompileOutput {
-				exit_status: ExitReason::Succeed(ExitSucceed::Returned),
-				cost,
-				logs,
-				output: v.finish(),
-			}),
-			Ok(None) => None,
-			Err(e) => Some(PrecompileOutput {
-				exit_status: ExitReason::Revert(ExitRevert::Reverted),
-				cost: 0,
-				logs: Default::default(),
-				output: AbiWriter::from(e).finish(),
-			}),
-		}
-	}
-}
-
-// TODO: This function is slow, and output can be memoized
-pub fn generate_transaction(collection_id: u32, chain_id: u64) -> ethereum::Transaction {
-	// FIXME: Can be done on wasm runtime with https://github.com/paritytech/substrate/pull/8728
-	#[cfg(feature = "std")]
-	{
-		let contract = collection_id_to_address(collection_id);
-		let signed = ethereum_tx_sign::RawTransaction {
-			nonce: 0.into(),
-			to: Some(contract.0.into()),
-			value: 0.into(),
-			gas_price: 0.into(),
-			gas: 0.into(),
-			// zero selector, this transaction always have same sender, so all data should be acquired from logs
-			data: Vec::from([0, 0, 0, 0]),
-		}
-		.sign(
-			// TODO: move to pallet config
-			// 0xF70631E55faff9f3FD3681545aa6c724226a3853
-			// 9dbaef9b3ebc00e53f67c6a77bcfbf2c4f2aebe4d70d94af4f2df01744b7a91a
-			&hex_literal::hex!("9dbaef9b3ebc00e53f67c6a77bcfbf2c4f2aebe4d70d94af4f2df01744b7a91a")
-				.into(),
-			&chain_id,
-		);
-		rlp::decode::<ethereum::Transaction>(&signed)
-			.expect("transaction is just created, it can't be broken")
-	}
-	#[cfg(not(feature = "std"))]
-	{
-		panic!("transaction generation not yet supported by wasm runtime while generating transaction for collection_id {}, chain_id {}", collection_id, chain_id)
+		let result = match collection.mode {
+			CollectionMode::NFT => {
+				call_internal::<UniqueNFTCall, _>(*source, &mut collection, value, input)
+			}
+			CollectionMode::Fungible(_) => {
+				call_internal::<UniqueFungibleCall, _>(*source, &mut collection, value, input)
+			}
+			_ => return None,
+		};
+		collection.recorder.evm_to_precompile_output(result)
 	}
 }
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -36,14 +36,12 @@
 use sp_std::vec;
 use sp_runtime::sp_std::prelude::Vec;
 use core::ops::{Deref, DerefMut};
-use core::cell::RefCell;
 use nft_data_structs::{
 	MAX_DECIMAL_POINTS, MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP, MAX_REFUNGIBLE_PIECES,
 	AccessMode, ChainLimits, Collection, CreateItemData, CollectionLimits, CollectionId,
 	CollectionMode, TokenId, SchemaVersion, SponsorshipState, Ownership, NftItemType,
 	FungibleItemType, ReFungibleItemType,
 };
-use pallet_ethereum::EthereumTransactionSender;
 
 #[cfg(test)]
 mod mock;
@@ -55,6 +53,7 @@
 mod eth;
 mod sponsorship;
 pub use sponsorship::NftSponsorshipHandler;
+pub use eth::sponsoring::NftEthSponsorshipHandler;
 
 pub use eth::NftErcSupport;
 pub use eth::account::*;
@@ -178,42 +177,39 @@
 	}
 }
 
+#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]
 pub struct CollectionHandle<T: Config> {
 	pub id: CollectionId,
 	collection: Collection<T>,
-	logs: eth::log::LogRecorder,
-	evm_address: H160,
-	gas_limit: RefCell<u64>,
+	recorder: pallet_evm_coder_substrate::SubstrateRecorder<T>,
 }
 impl<T: Config> CollectionHandle<T> {
 	pub fn get_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {
 		<CollectionById<T>>::get(id).map(|collection| Self {
 			id,
 			collection,
-			logs: eth::log::LogRecorder::default(),
-			evm_address: eth::collection_id_to_address(id),
-			gas_limit: RefCell::new(gas_limit),
+			recorder: pallet_evm_coder_substrate::SubstrateRecorder::new(
+				eth::collection_id_to_address(id),
+				gas_limit,
+			),
 		})
 	}
 	pub fn get(id: CollectionId) -> Option<Self> {
 		Self::get_with_gas_limit(id, u64::MAX)
 	}
-	pub fn gas_left(&self) -> u64 {
-		*self.gas_limit.borrow()
+	pub fn log(&self, log: impl evm_coder::ToLog) -> DispatchResult {
+		self.recorder.log_sub(log)
 	}
-	pub fn consume_gas(&self, gas: u64) -> DispatchResult {
-		let mut gas_limit = self.gas_limit.borrow_mut();
-		if *gas_limit < gas {
-			fail!(Error::<T>::OutOfGas);
-		}
-		*gas_limit -= gas;
-		Ok(())
+	fn consume_gas(&self, gas: u64) -> DispatchResult {
+		self.recorder.consume_gas_sub(gas)
 	}
-	pub fn log(&self, log: impl evm_coder::ToLog) {
-		self.logs.log(log.to_log(self.evm_address))
+	pub fn submit_logs(self) -> DispatchResult {
+		self.recorder.submit_logs()
 	}
-	pub fn into_inner(self) -> Collection<T> {
-		self.collection
+	pub fn save(self) -> DispatchResult {
+		self.recorder.submit_logs()?;
+		<CollectionById<T>>::insert(self.id, self.collection);
+		Ok(())
 	}
 }
 impl<T: Config> Deref for CollectionHandle<T> {
@@ -230,7 +226,7 @@
 	}
 }
 
-pub trait Config: system::Config + Sized {
+pub trait Config: system::Config + pallet_evm_coder_substrate::Config + Sized {
 	type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;
 
 	/// Weight information for extrinsics in this pallet.
@@ -245,9 +241,6 @@
 		<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,
 	>;
 	type TreasuryAccountId: Get<Self::AccountId>;
-
-	type EthereumChainId: Get<u64>;
-	type EthereumTransactionSender: pallet_ethereum::EthereumTransactionSender;
 }
 
 // # Used definitions
@@ -564,23 +557,23 @@
 				fail!(Error::<T>::NoPermission);
 			}
 
-			<AddressTokens<T>>::remove_prefix(collection_id);
-			<Allowances<T>>::remove_prefix(collection_id);
-			<Balance<T>>::remove_prefix(collection_id);
+			<AddressTokens<T>>::remove_prefix(collection_id, None);
+			<Allowances<T>>::remove_prefix(collection_id, None);
+			<Balance<T>>::remove_prefix(collection_id, None);
 			<ItemListIndex>::remove(collection_id);
 			<AdminList<T>>::remove(collection_id);
 			<CollectionById<T>>::remove(collection_id);
-			<WhiteList<T>>::remove_prefix(collection_id);
+			<WhiteList<T>>::remove_prefix(collection_id, None);
 
-			<NftItemList<T>>::remove_prefix(collection_id);
-			<FungibleItemList<T>>::remove_prefix(collection_id);
-			<ReFungibleItemList<T>>::remove_prefix(collection_id);
+			<NftItemList<T>>::remove_prefix(collection_id, None);
+			<FungibleItemList<T>>::remove_prefix(collection_id, None);
+			<ReFungibleItemList<T>>::remove_prefix(collection_id, None);
 
-			<NftTransferBasket<T>>::remove_prefix(collection_id);
-			<FungibleTransferBasket<T>>::remove_prefix(collection_id);
-			<ReFungibleTransferBasket<T>>::remove_prefix(collection_id);
+			<NftTransferBasket<T>>::remove_prefix(collection_id, None);
+			<FungibleTransferBasket<T>>::remove_prefix(collection_id, None);
+			<ReFungibleTransferBasket<T>>::remove_prefix(collection_id, None);
 
-			<VariableMetaDataBasket<T>>::remove_prefix(collection_id);
+			<VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);
 
 			DestroyedCollectionCount::put(DestroyedCollectionCount::get()
 				.checked_add(1)
@@ -667,9 +660,7 @@
 			let mut target_collection = Self::get_collection(collection_id)?;
 			Self::check_owner_permissions(&target_collection, &sender)?;
 			target_collection.access = mode;
-			Self::save_collection(target_collection);
-
-			Ok(())
+			target_collection.save()
 		}
 
 		/// Allows Anyone to create tokens if:
@@ -694,9 +685,7 @@
 			let mut target_collection = Self::get_collection(collection_id)?;
 			Self::check_owner_permissions(&target_collection, &sender)?;
 			target_collection.mint_mode = mint_permission;
-			Self::save_collection(target_collection);
-
-			Ok(())
+			target_collection.save()
 		}
 
 		/// Change the owner of the collection.
@@ -718,9 +707,7 @@
 			let mut target_collection = Self::get_collection(collection_id)?;
 			Self::check_owner_permissions(&target_collection, &sender)?;
 			target_collection.owner = new_owner;
-			Self::save_collection(target_collection);
-
-			Ok(())
+			target_collection.save()
 		}
 
 		/// Adds an admin of the Collection.
@@ -800,9 +787,7 @@
 			Self::check_owner_permissions(&target_collection, &sender)?;
 
 			target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);
-			Self::save_collection(target_collection);
-
-			Ok(())
+			target_collection.save()
 		}
 
 		/// # Permissions
@@ -824,9 +809,7 @@
 			);
 
 			target_collection.sponsorship = SponsorshipState::Confirmed(sender);
-			Self::save_collection(target_collection);
-
-			Ok(())
+			target_collection.save()
 		}
 
 		/// Switch back to pay-per-own-transaction model.
@@ -847,9 +830,7 @@
 			Self::check_owner_permissions(&target_collection, &sender)?;
 
 			target_collection.sponsorship = SponsorshipState::Disabled;
-			Self::save_collection(target_collection);
-
-			Ok(())
+			target_collection.save()
 		}
 
 		/// This method creates a concrete instance of NFT Collection created with CreateCollection method.
@@ -884,8 +865,7 @@
 
 			Self::create_item_internal(&sender, &collection, &owner, data)?;
 
-			Self::submit_logs(collection)?;
-			Ok(())
+			collection.submit_logs()
 		}
 
 		/// This method creates multiple items in a collection created with CreateCollection method.
@@ -918,8 +898,7 @@
 
 			Self::create_multiple_items_internal(&sender, &collection, &owner, items_data)?;
 
-			Self::submit_logs(collection)?;
-			Ok(())
+			collection.submit_logs()
 		}
 
 		/// Destroys a concrete instance of NFT.
@@ -944,8 +923,7 @@
 
 			Self::burn_item_internal(&sender, &target_collection, item_id, value)?;
 
-			Self::submit_logs(target_collection)?;
-			Ok(())
+			target_collection.submit_logs()
 		}
 
 		/// Change ownership of the token.
@@ -979,8 +957,7 @@
 
 			Self::transfer_internal(&sender, &recipient, &collection, item_id, value)?;
 
-			Self::submit_logs(collection)?;
-			Ok(())
+			collection.submit_logs()
 		}
 
 		/// Set, change, or remove approved address to transfer the ownership of the NFT.
@@ -1006,8 +983,7 @@
 
 			Self::approve_internal(&sender, &spender, &collection, item_id, amount)?;
 
-			Self::submit_logs(collection)?;
-			Ok(())
+			collection.submit_logs()
 		}
 
 		/// 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.
@@ -1037,8 +1013,7 @@
 
 			Self::transfer_from_internal(&sender, &from, &recipient, &collection, item_id, value)?;
 
-			Self::submit_logs(collection)?;
-			Ok(())
+			collection.submit_logs()
 		}
 		// #[weight = 0]
 		//     // let no_perm_mes = "You do not have permissions to modify this collection";
@@ -1107,9 +1082,7 @@
 			let mut target_collection = Self::get_collection(collection_id)?;
 			Self::check_owner_or_admin_permissions(&target_collection, &sender)?;
 			target_collection.schema_version = version;
-			Self::save_collection(target_collection);
-
-			Ok(())
+			target_collection.save()
 		}
 
 		/// Set off-chain data schema.
@@ -1139,9 +1112,7 @@
 			ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");
 
 			target_collection.offchain_schema = schema;
-			Self::save_collection(target_collection);
-
-			Ok(())
+			target_collection.save()
 		}
 
 		/// Set const on-chain data schema.
@@ -1171,9 +1142,7 @@
 			ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");
 
 			target_collection.const_on_chain_schema = schema;
-			Self::save_collection(target_collection);
-
-			Ok(())
+			target_collection.save()
 		}
 
 		/// Set variable on-chain data schema.
@@ -1203,9 +1172,7 @@
 			ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");
 
 			target_collection.variable_on_chain_schema = schema;
-			Self::save_collection(target_collection);
-
-			Ok(())
+			target_collection.save()
 		}
 
 		// Sudo permissions function
@@ -1253,9 +1220,8 @@
 			);
 
 			target_collection.limits = new_limits;
-			Self::save_collection(target_collection);
 
-			Ok(())
+			target_collection.save()
 		}
 	}
 }
@@ -1376,7 +1342,7 @@
 				owner: *sender.as_eth(),
 				approved: *spender.as_eth(),
 				token_id: item_id.into(),
-			});
+			})?;
 		}
 
 		if matches!(collection.mode, CollectionMode::Fungible(_)) {
@@ -1385,7 +1351,7 @@
 				owner: *sender.as_eth(),
 				spender: *spender.as_eth(),
 				value: allowance.into(),
-			});
+			})?;
 		}
 
 		Self::deposit_event(RawEvent::Approved(
@@ -1461,7 +1427,7 @@
 				owner: *from.as_eth(),
 				spender: *sender.as_eth(),
 				value: allowance.into(),
-			});
+			})?;
 		}
 
 		Ok(())
@@ -1789,7 +1755,7 @@
 			from: H160::default(),
 			to: *item_owner.as_eth(),
 			token_id: current_index.into(),
-		});
+		})?;
 		Self::deposit_event(RawEvent::ItemCreated(
 			collection_id,
 			current_index,
@@ -1886,7 +1852,7 @@
 			from: *owner.as_eth(),
 			to: H160::default(),
 			value: value.into(),
-		});
+		})?;
 		Ok(())
 	}
 
@@ -1894,22 +1860,8 @@
 		collection_id: CollectionId,
 	) -> Result<CollectionHandle<T>, sp_runtime::DispatchError> {
 		Ok(<CollectionHandle<T>>::get(collection_id).ok_or(Error::<T>::CollectionNotFound)?)
-	}
-
-	fn save_collection(collection: CollectionHandle<T>) {
-		<CollectionById<T>>::insert(collection.id, collection.into_inner());
 	}
 
-	pub fn submit_logs(collection: CollectionHandle<T>) -> DispatchResult {
-		if collection.logs.is_empty() {
-			return Ok(());
-		}
-		T::EthereumTransactionSender::submit_logs_transaction(
-			eth::generate_transaction(collection.id, T::EthereumChainId::get()),
-			collection.logs.retrieve_logs(),
-		)
-	}
-
 	fn check_owner_permissions(
 		target_collection: &CollectionHandle<T>,
 		subject: &T::AccountId,
@@ -2037,7 +1989,7 @@
 			from: *owner.as_eth(),
 			to: *recipient.as_eth(),
 			value: value.into(),
-		});
+		})?;
 		Self::deposit_event(RawEvent::Transfer(
 			collection.id,
 			1,
@@ -2173,7 +2125,7 @@
 			from: *sender.as_eth(),
 			to: *new_owner.as_eth(),
 			token_id: item_id.into(),
-		});
+		})?;
 		Self::deposit_event(RawEvent::Transfer(
 			collection.id,
 			item_id,
modifiedpallets/nft/src/mock.rsdiffbeforeafterboth
before · pallets/nft/src/mock.rs
1#![allow(clippy::from_over_into)]23use crate as pallet_template;4use sp_core::H256;5use frame_support::{parameter_types, weights::IdentityFee};6use sp_runtime::{7	traits::{BlakeTwo256, IdentityLookup},8	testing::Header,9	Perbill,10};11use pallet_transaction_payment::{CurrencyAdapter};12use frame_system as system;13use pallet_evm::AddressMapping;14use crate::{EvmBackwardsAddressMapping, CrossAccountId};15use codec::{Encode, Decode};1617type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;18type Block = frame_system::mocking::MockBlock<Test>;1920// Configure a mock runtime to test the pallet.21frame_support::construct_runtime!(22	pub enum Test where23		Block = Block,24		NodeBlock = Block,25		UncheckedExtrinsic = UncheckedExtrinsic,26	{27		System: frame_system::{Pallet, Call, Config, Storage, Event<T>},28		TemplateModule: pallet_template::{Pallet, Call, Storage},29		Balances: pallet_balances::{Pallet, Call, Storage},30	}31);3233parameter_types! {34	pub const BlockHashCount: u64 = 250;35	pub const SS58Prefix: u8 = 42;36}3738impl system::Config for Test {39	type BaseCallFilter = ();40	type BlockWeights = ();41	type BlockLength = ();42	type DbWeight = ();43	type Origin = Origin;44	type Call = Call;45	type Index = u64;46	type BlockNumber = u64;47	type Hash = H256;48	type Hashing = BlakeTwo256;49	type AccountId = u64;50	type Lookup = IdentityLookup<Self::AccountId>;51	type Header = Header;52	type Event = ();53	type BlockHashCount = BlockHashCount;54	type Version = ();55	type PalletInfo = PalletInfo;56	type AccountData = pallet_balances::AccountData<u64>;57	type OnNewAccount = ();58	type OnKilledAccount = ();59	type SystemWeightInfo = ();60	type SS58Prefix = SS58Prefix;61	type OnSetCode = ();62}6364parameter_types! {65	pub const ExistentialDeposit: u64 = 1;66	pub const MaxLocks: u32 = 50;67}68//frame_system::Module<Test>;69impl pallet_balances::Config for Test {70	type AccountStore = System;71	type Balance = u64;72	type DustRemoval = ();73	type Event = ();74	type ExistentialDeposit = ExistentialDeposit;75	type WeightInfo = ();76	type MaxLocks = MaxLocks;77}7879parameter_types! {80	pub const TransactionByteFee: u64 = 1;81}8283impl pallet_transaction_payment::Config for Test {84	type OnChargeTransaction = CurrencyAdapter<pallet_balances::Pallet<Test>, ()>;85	type TransactionByteFee = TransactionByteFee;86	type WeightToFee = IdentityFee<u64>;87	type FeeMultiplierUpdate = ();88}8990parameter_types! {91	pub const MinimumPeriod: u64 = 1;92}93impl pallet_timestamp::Config for Test {94	type Moment = u64;95	type OnTimestampSet = ();96	type MinimumPeriod = MinimumPeriod;97	type WeightInfo = ();98}99100type Timestamp = pallet_timestamp::Pallet<Test>;101type Randomness = pallet_randomness_collective_flip::Pallet<Test>;102103parameter_types! {104	pub const TombstoneDeposit: u64 = 1;105	pub const DepositPerContract: u64 = 1;106	pub const DepositPerStorageByte: u64 = 1;107	pub const DepositPerStorageItem: u64 = 1;108	pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * 24 * 60 * 10);109	pub const SurchargeReward: u64 = 1;110	pub const SignedClaimHandicap: u32 = 2;111	pub DeletionWeightLimit: u64 = u64::MAX;//Perbill::from_percent(10);112	pub DeletionQueueDepth: u32 = 10;113	pub Schedule: pallet_contracts::Schedule<Test> = Default::default();114}115116impl pallet_contracts::Config for Test {117	type Time = Timestamp;118	type Randomness = Randomness;119	type Currency = pallet_balances::Pallet<Test>;120	type Event = ();121	type RentPayment = ();122	type SignedClaimHandicap = SignedClaimHandicap;123	type TombstoneDeposit = TombstoneDeposit;124	type DepositPerContract = DepositPerContract;125	type DepositPerStorageByte = DepositPerStorageByte;126	type DepositPerStorageItem = DepositPerStorageItem;127	type RentFraction = RentFraction;128	type SurchargeReward = SurchargeReward;129	type DeletionWeightLimit = DeletionWeightLimit;130	type DeletionQueueDepth = DeletionQueueDepth;131	type ChainExtension = ();132	type WeightPrice = ();133	type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;134	type Schedule = Schedule;135	type CallStack = [pallet_contracts::Frame<Self>; 31];136}137138parameter_types! {139	pub const CollectionCreationPrice: u32 = 0;140	pub TreasuryAccountId: u64 = 1234;141	pub EthereumChainId: u32 = 1111;142}143144pub struct TestEvmAddressMapping;145impl AddressMapping<u64> for TestEvmAddressMapping {146	fn into_account_id(_addr: sp_core::H160) -> u64 {147		unimplemented!()148	}149}150151pub struct TestEvmBackwardsAddressMapping;152impl EvmBackwardsAddressMapping<u64> for TestEvmBackwardsAddressMapping {153	fn from_account_id(_account_id: u64) -> sp_core::H160 {154		unimplemented!()155	}156}157158#[derive(Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]159pub struct TestCrossAccountId(u64, sp_core::H160);160impl CrossAccountId<u64> for TestCrossAccountId {161	fn from_sub(sub: u64) -> Self {162		let mut eth = [0; 20];163		eth[12..20].copy_from_slice(&sub.to_be_bytes());164		Self(sub, sp_core::H160(eth))165	}166	fn as_sub(&self) -> &u64 {167		&self.0168	}169	fn from_eth(_eth: sp_core::H160) -> Self {170		unimplemented!()171	}172	fn as_eth(&self) -> &sp_core::H160 {173		&self.1174	}175}176177pub struct TestEtheremTransactionSender;178impl pallet_ethereum::EthereumTransactionSender for TestEtheremTransactionSender {179	fn submit_logs_transaction(180		_tx: pallet_ethereum::Transaction,181		_logs: Vec<pallet_ethereum::Log>,182	) -> Result<(), sp_runtime::DispatchError> {183		Ok(())184	}185}186187impl pallet_template::Config for Test {188	type Event = ();189	type WeightInfo = ();190	type CollectionCreationPrice = CollectionCreationPrice;191	type Currency = pallet_balances::Pallet<Test>;192	type TreasuryAccountId = TreasuryAccountId;193	type EvmAddressMapping = TestEvmAddressMapping;194	type EvmBackwardsAddressMapping = TestEvmBackwardsAddressMapping;195	type CrossAccountId = TestCrossAccountId;196	type EthereumChainId = EthereumChainId;197	type EthereumTransactionSender = TestEtheremTransactionSender;198}199200// Build genesis storage according to the mock runtime.201pub fn new_test_ext() -> sp_io::TestExternalities {202	system::GenesisConfig::default()203		.build_storage::<Test>()204		.unwrap()205		.into()206}
after · pallets/nft/src/mock.rs
1#![allow(clippy::from_over_into)]23use crate as pallet_template;4use sp_core::H256;5use frame_support::{parameter_types, weights::IdentityFee};6use sp_runtime::{7	traits::{BlakeTwo256, IdentityLookup},8	testing::Header,9	Perbill,10};11use pallet_transaction_payment::{CurrencyAdapter};12use frame_system as system;13use pallet_evm::AddressMapping;14use crate::{EvmBackwardsAddressMapping, CrossAccountId};15use codec::{Encode, Decode};1617type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;18type Block = frame_system::mocking::MockBlock<Test>;1920// Configure a mock runtime to test the pallet.21frame_support::construct_runtime!(22	pub enum Test where23		Block = Block,24		NodeBlock = Block,25		UncheckedExtrinsic = UncheckedExtrinsic,26	{27		System: frame_system::{Pallet, Call, Config, Storage, Event<T>},28		TemplateModule: pallet_template::{Pallet, Call, Storage},29		Balances: pallet_balances::{Pallet, Call, Storage},30	}31);3233parameter_types! {34	pub const BlockHashCount: u64 = 250;35	pub const SS58Prefix: u8 = 42;36}3738impl system::Config for Test {39	type BaseCallFilter = ();40	type BlockWeights = ();41	type BlockLength = ();42	type DbWeight = ();43	type Origin = Origin;44	type Call = Call;45	type Index = u64;46	type BlockNumber = u64;47	type Hash = H256;48	type Hashing = BlakeTwo256;49	type AccountId = u64;50	type Lookup = IdentityLookup<Self::AccountId>;51	type Header = Header;52	type Event = ();53	type BlockHashCount = BlockHashCount;54	type Version = ();55	type PalletInfo = PalletInfo;56	type AccountData = pallet_balances::AccountData<u64>;57	type OnNewAccount = ();58	type OnKilledAccount = ();59	type SystemWeightInfo = ();60	type SS58Prefix = SS58Prefix;61	type OnSetCode = ();62}6364parameter_types! {65	pub const ExistentialDeposit: u64 = 1;66	pub const MaxLocks: u32 = 50;67}68//frame_system::Module<Test>;69impl pallet_balances::Config for Test {70	type AccountStore = System;71	type Balance = u64;72	type DustRemoval = ();73	type Event = ();74	type ExistentialDeposit = ExistentialDeposit;75	type WeightInfo = ();76	type MaxLocks = MaxLocks;77}7879parameter_types! {80	pub const TransactionByteFee: u64 = 1;81}8283impl pallet_transaction_payment::Config for Test {84	type OnChargeTransaction = CurrencyAdapter<pallet_balances::Pallet<Test>, ()>;85	type TransactionByteFee = TransactionByteFee;86	type WeightToFee = IdentityFee<u64>;87	type FeeMultiplierUpdate = ();88}8990parameter_types! {91	pub const MinimumPeriod: u64 = 1;92}93impl pallet_timestamp::Config for Test {94	type Moment = u64;95	type OnTimestampSet = ();96	type MinimumPeriod = MinimumPeriod;97	type WeightInfo = ();98}99100type Timestamp = pallet_timestamp::Pallet<Test>;101type Randomness = pallet_randomness_collective_flip::Pallet<Test>;102103parameter_types! {104	pub const TombstoneDeposit: u64 = 1;105	pub const DepositPerContract: u64 = 1;106	pub const DepositPerStorageByte: u64 = 1;107	pub const DepositPerStorageItem: u64 = 1;108	pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * 24 * 60 * 10);109	pub const SurchargeReward: u64 = 1;110	pub const SignedClaimHandicap: u32 = 2;111	pub DeletionWeightLimit: u64 = u64::MAX;//Perbill::from_percent(10);112	pub DeletionQueueDepth: u32 = 10;113	pub Schedule: pallet_contracts::Schedule<Test> = Default::default();114}115116impl pallet_contracts::Config for Test {117	type Time = Timestamp;118	type Randomness = Randomness;119	type Currency = pallet_balances::Pallet<Test>;120	type Event = ();121	type RentPayment = ();122	type SignedClaimHandicap = SignedClaimHandicap;123	type TombstoneDeposit = TombstoneDeposit;124	type DepositPerContract = DepositPerContract;125	type DepositPerStorageByte = DepositPerStorageByte;126	type DepositPerStorageItem = DepositPerStorageItem;127	type RentFraction = RentFraction;128	type SurchargeReward = SurchargeReward;129	type DeletionWeightLimit = DeletionWeightLimit;130	type DeletionQueueDepth = DeletionQueueDepth;131	type ChainExtension = ();132	type WeightPrice = ();133	type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;134	type Schedule = Schedule;135	type CallStack = [pallet_contracts::Frame<Self>; 31];136}137138parameter_types! {139	pub const CollectionCreationPrice: u32 = 0;140	pub TreasuryAccountId: u64 = 1234;141	pub EthereumChainId: u32 = 1111;142}143144pub struct TestEvmAddressMapping;145impl AddressMapping<u64> for TestEvmAddressMapping {146	fn into_account_id(_addr: sp_core::H160) -> u64 {147		unimplemented!()148	}149}150151pub struct TestEvmBackwardsAddressMapping;152impl EvmBackwardsAddressMapping<u64> for TestEvmBackwardsAddressMapping {153	fn from_account_id(_account_id: u64) -> sp_core::H160 {154		unimplemented!()155	}156}157158#[derive(Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]159pub struct TestCrossAccountId(u64, sp_core::H160);160impl CrossAccountId<u64> for TestCrossAccountId {161	fn from_sub(sub: u64) -> Self {162		let mut eth = [0; 20];163		eth[12..20].copy_from_slice(&sub.to_be_bytes());164		Self(sub, sp_core::H160(eth))165	}166	fn as_sub(&self) -> &u64 {167		&self.0168	}169	fn from_eth(_eth: sp_core::H160) -> Self {170		unimplemented!()171	}172	fn as_eth(&self) -> &sp_core::H160 {173		&self.1174	}175}176177pub struct TestEtheremTransactionSender;178impl pallet_ethereum::EthereumTransactionSender for TestEtheremTransactionSender {179	fn submit_logs_transaction(180		_tx: pallet_ethereum::Transaction,181		_logs: Vec<pallet_ethereum::Log>,182	) -> Result<(), sp_runtime::DispatchError> {183		Ok(())184	}185}186187impl pallet_template::Config for Test {188	type Event = ();189	type WeightInfo = ();190	type CollectionCreationPrice = CollectionCreationPrice;191	type Currency = pallet_balances::Pallet<Test>;192	type TreasuryAccountId = TreasuryAccountId;193	type EvmAddressMapping = TestEvmAddressMapping;194	type EvmBackwardsAddressMapping = TestEvmBackwardsAddressMapping;195	type CrossAccountId = TestCrossAccountId;196	type EthereumTransactionSender = TestEtheremTransactionSender;197}198199// Build genesis storage according to the mock runtime.200pub fn new_test_ext() -> sp_io::TestExternalities {201	system::GenesisConfig::default()202		.build_storage::<Test>()203		.unwrap()204		.into()205}