difftreelog
refactor rewrite nft pallet to evm helpers
in: master
7 files changed
pallets/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"
pallets/nft/src/eth/erc.rsdiffbeforeafterboth1use core::char::{decode_utf16, REPLACEMENT_CHARACTER};1use evm_coder::{solidity_interface, solidity, types::*, ToLog};2use evm_coder::{ToLog, execution::Result, solidity, solidity_interface, types::*};3use core::convert::TryInto;4use alloc::format;5use crate::{Allowances, Module, Balance, CollectionHandle, CollectionMode, Config, NftItemList};6use frame_support::storage::StorageDoubleMap;7use pallet_evm::AddressMapping;8use super::account::CrossAccountId;2use sp_std::vec::Vec;9use sp_std::vec::Vec;3104#[solidity_interface]11#[solidity_interface(name = "ERC165")]5pub trait InlineNameSymbol {6 type Error;78 fn name(&self) -> Result<string, Self::Error>;12impl<T: Config> CollectionHandle<T> {9 fn symbol(&self) -> Result<string, Self::Error>;13 fn supports_interface(&self, interface_id: bytes4) -> Result<bool> {10}14 Ok(match self.mode {15 CollectionMode::Fungible(_) => UniqueFungibleCall::supports_interface(interface_id),16 CollectionMode::NFT => UniqueNFTCall::supports_interface(interface_id),17 _ => false,18 })19 }20}112112#[solidity_interface]22#[solidity_interface(name = "InlineNameSymbol")]13pub trait InlineTotalSupply {23impl<T: Config> CollectionHandle<T> {14 type Error;24 fn name(&self) -> Result<string> {25 Ok(decode_utf16(self.name.iter().copied())26 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))27 .collect::<string>())28 }152916 fn total_supply(&self) -> Result<uint256, Self::Error>;30 fn symbol(&self) -> Result<string> {31 Ok(string::from_utf8_lossy(&self.token_prefix).into())32 }17}33}183419#[solidity_interface]35#[solidity_interface(name = "InlineTotalSupply")]20pub trait ERC165 {36impl<T: Config> CollectionHandle<T> {21 type Error;2223 fn supports_interface(&self, interface_id: bytes4) -> Result<bool, Self::Error>;37 fn total_supply(&self) -> Result<uint256> {24}38 // TODO: we do not track total amount of all tokens39 Ok(0.into())40 }41}254226#[solidity_interface(inline_is(InlineNameSymbol))]43#[solidity_interface(name = "ERC721Metadata", inline_is(InlineNameSymbol))]27pub trait ERC721Metadata {44impl<T: Config> CollectionHandle<T> {28 type Error;2930 #[solidity(rename_selector = "tokenURI")]31 fn token_uri(&self, token_id: uint256) -> Result<string, Self::Error>;45 fn token_uri(&self, token_id: uint256) -> Result<string> {32}46 // TODO: We should standartize url prefix, maybe via offchain schema?47 Ok(format!("unique.network/{}/{}", self.id, token_id))48 }49}335034#[solidity_interface(inline_is(InlineTotalSupply))]51#[solidity_interface(name = "ERC721Enumerable", inline_is(InlineTotalSupply))]35pub trait ERC721Enumerable {52impl<T: Config> CollectionHandle<T> {36 type Error;3738 fn token_by_index(&self, index: uint256) -> Result<uint256, Self::Error>;53 fn token_by_index(&self, index: uint256) -> Result<uint256> {54 Ok(index)55 }5639 fn token_of_owner_by_index(57 fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {40 &self,58 // TODO: Not implemetable41 owner: address,59 Err("not implemented".into())42 index: uint256,60 }43 ) -> Result<uint256, Self::Error>;61}44}456246#[derive(ToLog)]63#[derive(ToLog)]47pub enum ERC721Events {64pub enum ERC721Events {71 },88 },72}89}739074#[solidity_interface(is(ERC165), events(ERC721Events))]91#[solidity_interface(name = "ERC721", is(ERC165), events(ERC721Events))]75pub trait ERC721 {92impl<T: Config> CollectionHandle<T> {76 type Error;93 #[solidity(rename_selector = "balanceOf")]7778 fn balance_of(&self, owner: address) -> Result<uint256, Self::Error>;94 fn balance_of_nft(&self, owner: address) -> Result<uint256> {95 let owner = T::EvmAddressMapping::into_account_id(owner);96 let balance = <Balance<T>>::get(self.id, owner);97 Ok(balance.into())98 }79 fn owner_of(&self, token_id: uint256) -> Result<address, Self::Error>;99 fn owner_of(&self, token_id: uint256) -> Result<address> {80100 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;81 #[solidity(rename_selector = "safeTransferFrom")]101 let token = <NftItemList<T>>::get(self.id, token_id).ok_or("unknown token")?;102 Ok(*token.owner.as_eth())103 }82 fn safe_transfer_from_with_data(104 fn safe_transfer_from_with_data(83 &mut self,105 &mut self,84 from: address,106 _from: address,85 to: address,107 _to: address,86 token_id: uint256,108 _token_id: uint256,87 data: bytes,109 _data: bytes,88 value: value,110 _value: value,89 ) -> Result<void, Self::Error>;111 ) -> Result<void> {112 // TODO: Not implemetable113 Err("not implemented".into())114 }90 fn safe_transfer_from(115 fn safe_transfer_from(91 &mut self,116 &mut self,92 from: address,117 _from: address,93 to: address,118 _to: address,94 token_id: uint256,119 _token_id: uint256,95 value: value,120 _value: value,96 ) -> Result<void, Self::Error>;121 ) -> Result<void> {122 // TODO: Not implemetable123 Err("not implemented".into())124 }9712598 fn transfer_from(126 fn transfer_from(99 &mut self,127 &mut self,100 caller: caller,128 caller: caller,101 from: address,129 from: address,102 to: address,130 to: address,103 token_id: uint256,131 token_id: uint256,104 value: value,132 _value: value,105 ) -> Result<void, Self::Error>;133 ) -> Result<void> {134 let caller = T::CrossAccountId::from_eth(caller);135 let from = T::CrossAccountId::from_eth(from);136 let to = T::CrossAccountId::from_eth(to);137 let token_id = token_id.try_into().map_err(|_| "token_id overflow")?;138139 <Module<T>>::transfer_from_internal(&caller, &from, &to, self, token_id, 1)140 .map_err(|_| "transferFrom error")?;141 Ok(())142 }143106 fn approve(144 fn approve(107 &mut self,145 &mut self,108 caller: caller,146 caller: caller,109 approved: address,147 approved: address,110 token_id: uint256,148 token_id: uint256,111 value: value,149 _value: value,112 ) -> Result<void, Self::Error>;150 ) -> Result<void> {151 let caller = T::CrossAccountId::from_eth(caller);152 let approved = T::CrossAccountId::from_eth(approved);153 let token_id = token_id.try_into().map_err(|_| "token_id overflow")?;154155 <Module<T>>::approve_internal(&caller, &approved, self, token_id, 1)156 .map_err(|_| "approve internal")?;157 Ok(())158 }159113 fn set_approval_for_all(160 fn set_approval_for_all(114 &mut self,161 &mut self,115 caller: caller,162 _caller: caller,116 operator: address,163 _operator: address,117 approved: bool,164 _approved: bool,118 ) -> Result<void, Self::Error>;165 ) -> Result<void> {166 // TODO: Not implemetable167 Err("not implemented".into())168 }119169120 fn get_approved(&self, token_id: uint256) -> Result<address, Self::Error>;170 fn get_approved(&self, _token_id: uint256) -> Result<address> {171 // TODO: Not implemetable172 Err("not implemented".into())173 }174121 fn is_approved_for_all(175 fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {122 &self,176 // TODO: Not implemetable123 owner: address,177 Err("not implemented".into())124 operator: address,178 }125 ) -> Result<address, Self::Error>;126}179}127180128#[solidity_interface]181#[solidity_interface(name = "ERC721UniqueExtensions")]129pub trait ERC721UniqueExtensions {182impl<T: Config> CollectionHandle<T> {130 type Error;183 #[solidity(rename_selector = "transfer")]131132 fn transfer(184 fn transfer_nft(133 &mut self,185 &mut self,134 caller: caller,186 caller: caller,135 to: address,187 to: address,136 token_id: uint256,188 token_id: uint256,137 value: value,189 _value: value,138 ) -> Result<void, Self::Error>;190 ) -> Result<void> {191 let caller = T::CrossAccountId::from_eth(caller);192 let to = T::CrossAccountId::from_eth(to);193 let token_id = token_id.try_into().map_err(|_| "amount overflow")?;194195 <Module<T>>::transfer_internal(&caller, &to, self, token_id, 1)196 .map_err(|_| "transfer error")?;197 Ok(())198 }139}199}140200141#[solidity_interface(is(201#[solidity_interface(202 name = "UniqueNFT",203 is(142 ERC165,204 ERC165,143 ERC721,205 ERC721,144 ERC721Metadata,206 ERC721Metadata,145 ERC721Enumerable,207 ERC721Enumerable,146 ERC721UniqueExtensions208 ERC721UniqueExtensions147))]209 )148pub trait UniqueNFT {210)]149 type Error;211impl<T: Config> CollectionHandle<T> {}150}151212152#[derive(ToLog)]213#[derive(ToLog)]153pub enum ERC20Events {214pub enum ERC20Events {168}229}169230170#[solidity_interface(inline_is(InlineNameSymbol, InlineTotalSupply), events(ERC20Events))]231#[solidity_interface(171pub trait ERC20 {232 name = "ERC20",172 type Error;233 inline_is(InlineNameSymbol, InlineTotalSupply),173234 events(ERC20Events)235)]236impl<T: Config> CollectionHandle<T> {174 fn decimals(&self) -> Result<uint8, Self::Error>;237 fn decimals(&self) -> Result<uint8> {238 Ok(if let CollectionMode::Fungible(decimals) = &self.mode {239 *decimals240 } else {241 unreachable!()242 })243 }175 fn balance_of(&self, owner: address) -> Result<uint256, Self::Error>;244 fn balance_of(&self, owner: address) -> Result<uint256> {245 let owner = T::EvmAddressMapping::into_account_id(owner);246 let balance = <Balance<T>>::get(self.id, owner);247 Ok(balance.into())248 }176 fn transfer(249 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {177 &mut self,178 caller: caller,179 to: address,180 value: uint256,181 ) -> Result<bool, Self::Error>;250 let caller = T::CrossAccountId::from_eth(caller);251 let to = T::CrossAccountId::from_eth(to);252 let amount = amount.try_into().map_err(|_| "amount overflow")?;253254 <Module<T>>::transfer_internal(&caller, &to, self, 1, amount)255 .map_err(|_| "transfer error")?;256 Ok(true)257 }258 #[solidity(rename_selector = "transferFrom")]182 fn transfer_from(259 fn transfer_from_fungible(183 &mut self,260 &mut self,184 caller: caller,261 caller: caller,185 from: address,262 from: address,186 to: address,263 to: address,187 value: uint256,264 amount: uint256,188 ) -> Result<bool, Self::Error>;265 ) -> Result<bool> {266 let caller = T::CrossAccountId::from_eth(caller);267 let from = T::CrossAccountId::from_eth(from);268 let to = T::CrossAccountId::from_eth(to);269 let amount = amount.try_into().map_err(|_| "amount overflow")?;270271 <Module<T>>::transfer_from_internal(&caller, &from, &to, self, 1, amount)272 .map_err(|_| "transferFrom error")?;273 Ok(true)274 }275 #[solidity(rename_selector = "approve")]189 fn approve(276 fn approve_fungible(190 &mut self,277 &mut self,191 caller: caller,278 caller: caller,192 spender: address,279 spender: address,193 value: uint256,280 amount: uint256,194 ) -> Result<bool, Self::Error>;281 ) -> Result<bool> {282 let caller = T::CrossAccountId::from_eth(caller);283 let spender = T::CrossAccountId::from_eth(spender);284 let amount = amount.try_into().map_err(|_| "amount overflow")?;285286 <Module<T>>::approve_internal(&caller, &spender, self, 1, amount)287 .map_err(|_| "approve internal")?;288 Ok(true)289 }195 fn allowance(&self, owner: address, spender: address) -> Result<uint256, Self::Error>;290 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {196}291 let owner = T::CrossAccountId::from_eth(owner);292 let spender = T::CrossAccountId::from_eth(spender);293294 Ok(<Allowances<T>>::get(self.id, (1, owner.as_sub(), spender.as_sub())).into())295 }296}197297198#[solidity_interface(is(ERC165, ERC20))]298#[solidity_interface(name = "UniqueFungible", is(ERC165, ERC20))]199pub trait UniqueFungible {299impl<T: Config> CollectionHandle<T> {}200 type Error;201}202300pallets/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)
- }
-}
pallets/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()
- }
-}
pallets/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)
}
}
pallets/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,
pallets/nft/src/mock.rsdiffbeforeafterboth--- a/pallets/nft/src/mock.rs
+++ b/pallets/nft/src/mock.rs
@@ -193,7 +193,6 @@
type EvmAddressMapping = TestEvmAddressMapping;
type EvmBackwardsAddressMapping = TestEvmBackwardsAddressMapping;
type CrossAccountId = TestCrossAccountId;
- type EthereumChainId = EthereumChainId;
type EthereumTransactionSender = TestEtheremTransactionSender;
}