difftreelog
refactor share unq sponsoring code with evm
in: master
4 files changed
pallets/nft/src/eth/sponsoring.rsdiffbeforeafterboth1//! Implements EVM sponsoring logic via OnChargeEVMTransaction1//! Implements EVM sponsoring logic via OnChargeEVMTransaction223use crate::{Collection, Config, FungibleTransferBasket, NftTransferBasket};3use crate::{Config, sponsorship::*};4use evm_coder::{Call, abi::AbiReader};4use evm_coder::{Call, abi::AbiReader};5use frame_support::{6 storage::{StorageDoubleMap},7};8use pallet_common::eth::map_eth_to_id;5use pallet_common::{CollectionHandle, eth::map_eth_to_id};9use sp_core::H160;6use sp_core::H160;10use sp_std::prelude::*;7use sp_std::prelude::*;11use up_sponsorship::SponsorshipHandler;8use up_sponsorship::SponsorshipHandler;12use core::marker::PhantomData;9use core::marker::PhantomData;13use core::convert::TryInto;10use core::convert::TryInto;14use nft_data_structs::{CollectionId, NFT_SPONSOR_TRANSFER_TIMEOUT, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT};11use nft_data_structs::TokenId;15use pallet_common::{12use up_evm_mapping::EvmBackwardsAddressMapping;16 CollectionById,13use pallet_evm::AddressMapping;17 account::{CrossAccountId, EvmBackwardsAddressMapping},18};191420use pallet_nonfungible::erc::{UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721Call};15use pallet_nonfungible::erc::{UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721Call};21use pallet_fungible::erc::{UniqueFungibleCall, ERC20Call};16use pallet_fungible::erc::{UniqueFungibleCall, ERC20Call};2223struct AnyError;2425fn try_sponsor<T: Config>(26 caller: &H160,27 collection_id: CollectionId,28 collection: &Collection<T>,29 call: &[u8],30) -> Result<(), AnyError> {31 let (method_id, mut reader) = AbiReader::new_call(call).map_err(|_| AnyError)?;32 match &collection.mode {33 crate::CollectionMode::NFT => {34 let call: UniqueNFTCall = UniqueNFTCall::parse(method_id, &mut reader)35 .map_err(|_| AnyError)?36 .ok_or(AnyError)?;37 match call {38 UniqueNFTCall::ERC721UniqueExtensions(ERC721UniqueExtensionsCall::Transfer {39 token_id,40 ..41 })42 | UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => {43 let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?;44 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;45 let collection_limits = &collection.limits;46 let limit =47 collection_limits.sponsor_transfer_timeout(NFT_SPONSOR_TRANSFER_TIMEOUT);4849 let mut sponsor = true;50 if <NftTransferBasket<T>>::contains_key(collection_id, token_id) {51 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, token_id);52 let limit_time = last_tx_block + limit.into();53 if block_number <= limit_time {54 sponsor = false;55 }56 }57 if sponsor {58 <NftTransferBasket<T>>::insert(collection_id, token_id, block_number);59 return Ok(());60 }61 }62 _ => {}63 }64 }65 crate::CollectionMode::Fungible(_) => {66 let call: UniqueFungibleCall = UniqueFungibleCall::parse(method_id, &mut reader)67 .map_err(|_| AnyError)?68 .ok_or(AnyError)?;69 #[allow(clippy::single_match)]70 match call {71 UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {72 let who = T::CrossAccountId::from_eth(*caller);73 let collection_limits = &collection.limits;74 let limit = collection_limits75 .sponsor_transfer_timeout(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT);7677 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;78 let mut sponsored = true;79 if <FungibleTransferBasket<T>>::contains_key(collection_id, who.as_sub()) {80 let last_tx_block =81 <FungibleTransferBasket<T>>::get(collection_id, who.as_sub());82 let limit_time = last_tx_block + limit.into();83 if block_number <= limit_time {84 sponsored = false;85 }86 }87 if sponsored {88 <FungibleTransferBasket<T>>::insert(89 collection_id,90 who.as_sub(),91 block_number,92 );93 return Ok(());94 }95 }96 _ => {}97 }98 }99 _ => {}100 }101 Err(AnyError)102}10317104pub struct NftEthSponsorshipHandler<T: Config>(PhantomData<*const T>);18pub struct NftEthSponsorshipHandler<T: Config>(PhantomData<*const T>);105impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for NftEthSponsorshipHandler<T> {19impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for NftEthSponsorshipHandler<T> {106 fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {20 fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {107 if let Some(collection_id) = map_eth_to_id(&call.0) {21 let collection_id = map_eth_to_id(&call.0)?;108 if let Some(collection) = <CollectionById<T>>::get(collection_id) {22 let collection = <CollectionHandle<T>>::new(collection_id)?;109 if !collection.sponsorship.confirmed() {23 let sponsor = collection.sponsorship.sponsor()?.clone();110 return None;24 let sponsor =111 }25 <T as pallet_common::Config>::EvmBackwardsAddressMapping::from_account_id(sponsor);26 let who = <T as pallet_common::Config>::EvmAddressMapping::into_account_id(*who);27 let (method_id, mut reader) = AbiReader::new_call(&call.1).ok()?;28 match &collection.mode {29 crate::CollectionMode::NFT => {30 let call = UniqueNFTCall::parse(method_id, &mut reader).ok()??;31 match call {32 UniqueNFTCall::ERC721UniqueExtensions(33 ERC721UniqueExtensionsCall::Transfer { token_id, .. },34 )35 | UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => {36 let token_id: TokenId = token_id.try_into().ok()?;112 if try_sponsor(who, collection_id, &collection, &call.1).is_ok() {37 withdraw_transfer::<T>(&collection, &who, &token_id).map(|()| sponsor)113 return collection38 }114 .sponsorship39 UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => {115 .sponsor()40 let token_id: TokenId = token_id.try_into().ok()?;116 .cloned()41 withdraw_approve::<T>(&collection, &who, &token_id).map(|()| sponsor)117 .map(T::EvmBackwardsAddressMapping::from_account_id);42 }118 }43 _ => None,119 }44 }120 }45 }46 crate::CollectionMode::Fungible(_) => {47 let call = UniqueFungibleCall::parse(method_id, &mut reader).ok()??;48 #[allow(clippy::single_match)]49 match call {50 UniqueFungibleCall::ERC20(51 ERC20Call::Transfer { .. } | ERC20Call::TransferFrom { .. },52 ) => withdraw_transfer::<T>(&collection, &who, &TokenId::default())53 .map(|()| sponsor),54 UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => {55 withdraw_approve::<T>(&collection, &who, &TokenId::default())56 .map(|()| sponsor)57 }58 _ => None,59 }60 }121 None61 _ => None,62 }122 }63 }123}64}12465pallets/nft/src/lib.rsdiffbeforeafterboth136 //#region Tokens transfer rate limit baskets136 //#region Tokens transfer rate limit baskets137 /// (Collection id (controlled?2), who created (real))137 /// (Collection id (controlled?2), who created (real))138 /// TODO: Off chain worker should remove from this map when collection gets removed138 /// TODO: Off chain worker should remove from this map when collection gets removed139 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => T::BlockNumber;139 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;140 /// Collection id (controlled?2), token id (controlled?2)140 /// Collection id (controlled?2), token id (controlled?2)141 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;141 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;142 /// Collection id (controlled?2), owning user (real)142 /// Collection id (controlled?2), owning user (real)143 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;143 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;144 /// Collection id (controlled?2), token id (controlled?2)144 /// Collection id (controlled?2), token id (controlled?2)145 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;145 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;146 //#endregion146 //#endregion147147148 /// Variable metadata sponsoring148 /// Variable metadata sponsoring253253254 <NftTransferBasket<T>>::remove_prefix(collection_id, None);254 <NftTransferBasket<T>>::remove_prefix(collection_id, None);255 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);255 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);256 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id, None);256 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);257257258 <VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);258 <VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);259 <NftApproveBasket<T>>::remove_prefix(collection_id, None);259 <NftApproveBasket<T>>::remove_prefix(collection_id, None);pallets/nft/src/sponsorship.rsdiffbeforeafterboth1use crate::{1use crate::{2 Config, Call, CreateItemBasket, VariableMetaDataBasket, ReFungibleTransferBasket,2 Config, Call, CreateItemBasket, VariableMetaDataBasket, ReFungibleTransferBasket,3 FungibleTransferBasket, NftTransferBasket, CreateItemData, CollectionMode,3 FungibleTransferBasket, NftTransferBasket, CreateItemData, CollectionMode, NftApproveBasket,4 FungibleApproveBasket, RefungibleApproveBasket,4};5};5use core::marker::PhantomData;6use core::marker::PhantomData;6use up_sponsorship::SponsorshipHandler;7use up_sponsorship::SponsorshipHandler;7use frame_support::{8use frame_support::{8 traits::{IsSubType},9 traits::{IsSubType},9 storage::{StorageMap, StorageDoubleMap},10 storage::{StorageMap, StorageDoubleMap, StorageNMap},10};11};11use nft_data_structs::{12use nft_data_structs::{12 TokenId, CollectionId, NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,13 CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, NFT_SPONSOR_TRANSFER_TIMEOUT,13 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,14 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId,14};15};15use pallet_common::{CollectionById};16use pallet_common::{CollectionHandle};1718pub fn withdraw_transfer<T: Config>(19 collection: &CollectionHandle<T>,20 who: &T::AccountId,21 item_id: &TokenId,22) -> Option<()> {23 // sponsor timeout24 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;25 let limit = collection26 .limits27 .sponsor_transfer_timeout(match collection.mode {28 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,29 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,30 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,31 });3233 let last_tx_block = match collection.mode {34 CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, item_id),35 CollectionMode::Fungible(_) => <FungibleTransferBasket<T>>::get(collection.id, who),36 CollectionMode::ReFungible => {37 <ReFungibleTransferBasket<T>>::get((collection.id, item_id, who))38 }39 };4041 if let Some(last_tx_block) = last_tx_block {42 let timeout = last_tx_block + limit.into();43 if block_number < timeout {44 return None;45 }46 }4748 match collection.mode {49 CollectionMode::NFT => <NftTransferBasket<T>>::insert(collection.id, item_id, block_number),50 CollectionMode::Fungible(_) => {51 <FungibleTransferBasket<T>>::insert(collection.id, who, block_number)52 }53 CollectionMode::ReFungible => {54 <ReFungibleTransferBasket<T>>::insert((collection.id, item_id, who), block_number)55 }56 };5758 Some(())59}6061pub fn withdraw_create_item<T: Config>(62 collection: &CollectionHandle<T>,63 who: &T::AccountId,64 _properties: &CreateItemData,65) -> Option<()> {66 if _properties.data_size() as u32 > collection.limits.sponsored_data_size() {67 return None;68 }6970 // sponsor timeout71 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;72 let limit = collection73 .limits74 .sponsor_transfer_timeout(match _properties {75 CreateItemData::NFT(_) => NFT_SPONSOR_TRANSFER_TIMEOUT,76 CreateItemData::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,77 CreateItemData::ReFungible(_) => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,78 });7980 if let Some(last_tx_block) = <CreateItemBasket<T>>::get((collection.id, &who)) {81 let timeout = last_tx_block + limit.into();82 if block_number < timeout {83 return None;84 }85 }8687 CreateItemBasket::<T>::insert((collection.id, who.clone()), block_number);8889 Some(())90}9192pub fn withdraw_set_variable_meta_data<T: Config>(93 collection: &CollectionHandle<T>,94 item_id: &TokenId,95 data: &[u8],96) -> Option<()> {97 // Can't sponsor fungible collection, this tx will be rejected98 // as invalid99 if matches!(collection.mode, CollectionMode::Fungible(_)) {100 return None;101 }102 if data.len() > collection.limits.sponsored_data_size() as usize {103 return None;104 }105106 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;107 let limit = collection.limits.sponsored_data_rate_limit()?;108109 if let Some(last_tx_block) = VariableMetaDataBasket::<T>::get(collection.id, item_id) {110 let timeout = last_tx_block + limit.into();111 if block_number < timeout {112 return None;113 }114 }115116 <VariableMetaDataBasket<T>>::insert(collection.id, item_id, block_number);117118 Some(())119}120121pub fn withdraw_approve<T: Config>(122 collection: &CollectionHandle<T>,123 who: &T::AccountId,124 item_id: &TokenId,125) -> Option<()> {126 // sponsor timeout127 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;128 let limit = collection.limits.sponsor_approve_timeout();129130 let last_tx_block = match collection.mode {131 CollectionMode::NFT => <NftApproveBasket<T>>::get(collection.id, item_id),132 CollectionMode::Fungible(_) => <FungibleApproveBasket<T>>::get(collection.id, who),133 CollectionMode::ReFungible => {134 <RefungibleApproveBasket<T>>::get((collection.id, item_id, who))135 }136 };137138 if let Some(last_tx_block) = last_tx_block {139 let timeout = last_tx_block + limit.into();140 if block_number < timeout {141 return None;142 }143 }144145 match collection.mode {146 CollectionMode::NFT => <NftApproveBasket<T>>::insert(collection.id, item_id, block_number),147 CollectionMode::Fungible(_) => {148 <FungibleApproveBasket<T>>::insert(collection.id, who, block_number)149 }150 CollectionMode::ReFungible => {151 <RefungibleApproveBasket<T>>::insert((collection.id, item_id, who), block_number)152 }153 };154155 Some(())156}157158fn load<T: Config>(id: CollectionId) -> Option<(T::AccountId, CollectionHandle<T>)> {159 let collection = CollectionHandle::new(id)?;160 let sponsor = collection.sponsorship.sponsor().cloned()?;161 Some((sponsor, collection))162}1616317pub struct NftSponsorshipHandler<T>(PhantomData<T>);164pub struct NftSponsorshipHandler<T>(PhantomData<T>);18impl<T: Config> NftSponsorshipHandler<T> {19 pub fn withdraw_create_item(20 who: &T::AccountId,21 collection_id: &CollectionId,22 _properties: &CreateItemData,23 ) -> Option<T::AccountId> {24 let collection = CollectionById::<T>::get(collection_id)?;2526 // sponsor timeout27 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;2829 let limit = collection30 .limits31 .sponsor_transfer_timeout(match _properties {32 CreateItemData::NFT(_) => NFT_SPONSOR_TRANSFER_TIMEOUT,33 CreateItemData::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,34 CreateItemData::ReFungible(_) => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,35 });36 if CreateItemBasket::<T>::contains_key((collection_id, &who)) {37 let last_tx_block = CreateItemBasket::<T>::get((collection_id, &who));38 let limit_time = last_tx_block + limit.into();39 if block_number <= limit_time {40 return None;41 }42 }43 CreateItemBasket::<T>::insert((collection_id, who.clone()), block_number);4445 // check free create limit46 if collection.limits.sponsored_data_size() >= (_properties.data_size() as u32) {47 collection.sponsorship.sponsor().cloned()48 } else {49 None50 }51 }5253 pub fn withdraw_transfer(54 who: &T::AccountId,55 collection_id: &CollectionId,56 item_id: &TokenId,57 ) -> Option<T::AccountId> {58 let collection = CollectionById::<T>::get(collection_id)?;5960 let mut sponsor_transfer = false;61 if collection.sponsorship.confirmed() {62 let collection_limits = collection.limits.clone();63 let collection_mode = collection.mode.clone();6465 // sponsor timeout66 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;67 sponsor_transfer = match collection_mode {68 CollectionMode::NFT => {69 // get correct limit70 let limit =71 collection_limits.sponsor_transfer_timeout(NFT_SPONSOR_TRANSFER_TIMEOUT);7273 let mut sponsored = true;74 if NftTransferBasket::<T>::contains_key(collection_id, item_id) {75 let last_tx_block = NftTransferBasket::<T>::get(collection_id, item_id);76 let limit_time = last_tx_block + limit.into();77 if block_number <= limit_time {78 sponsored = false;79 }80 }81 if sponsored {82 NftTransferBasket::<T>::insert(collection_id, item_id, block_number);83 }8485 sponsored86 }87 CollectionMode::Fungible(_) => {88 // get correct limit89 let limit = collection_limits90 .sponsor_transfer_timeout(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT);9192 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;93 let mut sponsored = true;94 if FungibleTransferBasket::<T>::contains_key(collection_id, who) {95 let last_tx_block = FungibleTransferBasket::<T>::get(collection_id, who);96 let limit_time = last_tx_block + limit.into();97 if block_number <= limit_time {98 sponsored = false;99 }100 }101 if sponsored {102 FungibleTransferBasket::<T>::insert(collection_id, who, block_number);103 }104105 sponsored106 }107 CollectionMode::ReFungible => {108 // get correct limit109 let limit = collection_limits110 .sponsor_transfer_timeout(REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT);111112 let mut sponsored = true;113 if ReFungibleTransferBasket::<T>::contains_key(collection_id, item_id) {114 let last_tx_block =115 ReFungibleTransferBasket::<T>::get(collection_id, item_id);116 let limit_time = last_tx_block + limit.into();117 if block_number <= limit_time {118 sponsored = false;119 }120 }121 if sponsored {122 ReFungibleTransferBasket::<T>::insert(collection_id, item_id, block_number);123 }124125 sponsored126 }127 };128 }129130 if !sponsor_transfer {131 None132 } else {133 collection.sponsorship.sponsor().cloned()134 }135 }136137 pub fn withdraw_set_variable_meta_data(138 collection_id: &CollectionId,139 item_id: &TokenId,140 data: &[u8],141 ) -> Option<T::AccountId> {142 let mut sponsor_metadata_changes = false;143144 let collection = CollectionById::<T>::get(collection_id)?;145146 if collection.sponsorship.confirmed() &&147 // Can't sponsor fungible collection, this tx will be rejected148 // as invalid149 !matches!(collection.mode, CollectionMode::Fungible(_)) &&150 data.len() <= collection.limits.sponsored_data_size() as usize151 {152 if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit() {153 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;154155 if VariableMetaDataBasket::<T>::get(collection_id, item_id)156 .map(|last_block| block_number - last_block > rate_limit.into())157 .unwrap_or(true)158 {159 sponsor_metadata_changes = true;160 VariableMetaDataBasket::<T>::insert(collection_id, item_id, block_number);161 }162 }163 }164165 if !sponsor_metadata_changes {166 None167 } else {168 collection.sponsorship.sponsor().cloned()169 }170 }171}172173impl<T, C> SponsorshipHandler<T::AccountId, C> for NftSponsorshipHandler<T>165impl<T, C> SponsorshipHandler<T::AccountId, C> for NftSponsorshipHandler<T>174where166where181 collection_id,173 collection_id,182 data,174 data,183 ..175 ..184 } => Self::withdraw_create_item(who, collection_id, data),176 } => {177 let (sponsor, collection) = load(*collection_id)?;178 withdraw_create_item::<T>(&collection, who, data).map(|()| sponsor)179 }185 Call::transfer {180 Call::transfer {186 collection_id,181 collection_id,187 item_id,182 item_id,188 ..183 ..189 } => Self::withdraw_transfer(who, collection_id, item_id),184 }185 | Call::transfer_from {186 collection_id,187 item_id,188 ..189 } => {190 let (sponsor, collection) = load(*collection_id)?;191 withdraw_transfer::<T>(&collection, who, item_id).map(|()| sponsor)192 }193 Call::approve {194 collection_id,195 item_id,196 ..197 } => {198 let (sponsor, collection) = load(*collection_id)?;199 withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)200 }190 Call::set_variable_meta_data {201 Call::set_variable_meta_data {191 collection_id,202 collection_id,192 item_id,203 item_id,193 data,204 data,194 } => Self::withdraw_set_variable_meta_data(collection_id, item_id, data),205 } => {206 let (sponsor, collection) = load(*collection_id)?;207 withdraw_set_variable_meta_data::<T>(&collection, item_id, data).map(|()| sponsor)208 }195 _ => None,209 _ => None,196 }210 }197 }211 }primitives/evm-mapping/src/lib.rsdiffbeforeafterboth4use sp_core::H160;4use sp_core::H160;556/// Transforms substrate addresses to ethereum (Reverse of `EvmAddressMapping`)6/// Transforms substrate addresses to ethereum (Reverse of `EvmAddressMapping`)7/// pallet_evm doesn't have this, as it only checks if eth address 7/// pallet_evm doesn't have this, as it only checks if eth address8/// is owned by substrate via `EnsureAddressOrigin` trait8/// is owned by substrate via `EnsureAddressOrigin` trait9/// 9///10/// This trait implementations shouldn't conflict with used `EnsureAddressOrigin`10/// This trait implementations shouldn't conflict with used `EnsureAddressOrigin`11pub trait EvmBackwardsAddressMapping<AccountId> {11pub trait EvmBackwardsAddressMapping<AccountId> {12 fn from_account_id(account_id: AccountId) -> H160;12 fn from_account_id(account_id: AccountId) -> H160;