1use crate::{AccountId, AssetId};
20
21use fp_evm::AccountProvider;
22use frame_support::{
23 ensure,
24 traits::{
25 fungible::{Balanced, Credit},
26 tokens::{fungible::Inspect, imbalance::OnUnbalanced},
27 },
28};
29use pallet_evm::{AddressMapping, HashedAddressMapping, OnChargeEVMTransaction};
30use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
31use scale_info::TypeInfo;
32pub use sp_core::{Hasher, H160, H256, U256};
33use sp_runtime::traits::UniqueSaturatedInto;
34use sp_std::marker::PhantomData;
35
36use pallet_assets::AssetsCallback;
37use pallet_evm_precompile_assets_erc20::AddressToAssetId;
38
39pub type EvmAddress = H160;
40
41pub const EVM_REVERT_CODE: &[u8] = &[0x60, 0x00, 0x60, 0x00, 0xfd];
43
44pub struct EvmRevertCodeHandler<A, R>(PhantomData<(A, R)>);
52impl<A, R> AssetsCallback<AssetId, AccountId> for EvmRevertCodeHandler<A, R>
53where
54 A: AddressToAssetId<AssetId>,
55 R: pallet_evm::Config,
56{
57 fn created(id: &AssetId, _: &AccountId) -> Result<(), ()> {
58 let address = A::asset_id_to_address(*id);
59 ensure!(!pallet_evm::AccountCodes::<R>::contains_key(&address), ());
61 pallet_evm::AccountCodes::<R>::insert(address, EVM_REVERT_CODE.to_vec());
62 Ok(())
63 }
64
65 fn destroyed(id: &AssetId) -> Result<(), ()> {
66 let address = A::asset_id_to_address(*id);
67 pallet_evm::AccountCodes::<R>::remove(address);
68 Ok(())
69 }
70}
71
72pub trait UnifiedAddressMapper<AccountId> {
74 fn to_account_id(evm_address: &EvmAddress) -> Option<AccountId>;
76
77 fn to_account_id_or_default(evm_address: &EvmAddress) -> UnifiedAddress<AccountId> {
81 Self::to_account_id(evm_address).map_or_else(
82 || UnifiedAddress::Default(Self::to_default_account_id(evm_address)),
84 |a| UnifiedAddress::Mapped(a),
85 )
86 }
87 fn to_default_account_id(evm_address: &EvmAddress) -> AccountId;
89
90 fn to_h160(account_id: &AccountId) -> Option<EvmAddress>;
92
93 fn to_h160_or_default(account_id: &AccountId) -> UnifiedAddress<H160> {
97 Self::to_h160(account_id).map_or_else(
98 || UnifiedAddress::Default(Self::to_default_h160(account_id)),
100 |a| UnifiedAddress::Mapped(a),
101 )
102 }
103
104 fn to_default_h160(account_id: &AccountId) -> EvmAddress;
106}
107
108pub struct HashedDefaultMappings<H>(PhantomData<H>);
110impl<H: Hasher<Out = H256>> UnifiedAddressMapper<AccountId> for HashedDefaultMappings<H> {
111 fn to_default_account_id(evm_address: &EvmAddress) -> AccountId {
112 HashedAddressMapping::<H>::into_account_id(*evm_address)
113 }
114
115 fn to_default_h160(account_id: &AccountId) -> EvmAddress {
116 let payload = (b"evm:", account_id);
117 H160::from_slice(&payload.using_encoded(H::hash)[0..20])
118 }
119
120 fn to_account_id(_: &EvmAddress) -> Option<AccountId> {
121 None
122 }
123
124 fn to_h160(_: &AccountId) -> Option<EvmAddress> {
125 None
126 }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)]
130pub enum UnifiedAddress<Address> {
131 #[codec(index = 0)]
134 Mapped(Address),
135 #[codec(index = 1)]
138 Default(Address),
139}
140
141impl<Address> UnifiedAddress<Address> {
142 pub fn into_address(self) -> Address {
144 match self {
145 Self::Default(a) => a,
146 Self::Mapped(a) => a,
147 }
148 }
149}
150
151pub struct EVMFungibleAdapterWrapper<F, FeeHandler, TipHandler>(
161 core::marker::PhantomData<(F, FeeHandler, TipHandler)>,
162);
163impl<T, F, FeeHandler, TipHandler> OnChargeEVMTransaction<T>
164 for EVMFungibleAdapterWrapper<F, FeeHandler, TipHandler>
165where
166 T: pallet_evm::Config,
167 F: Balanced<<T::AccountProvider as AccountProvider>::AccountId>,
168 FeeHandler: OnUnbalanced<Credit<<T::AccountProvider as AccountProvider>::AccountId, F>>,
169 TipHandler: OnUnbalanced<Credit<<T::AccountProvider as AccountProvider>::AccountId, F>>,
170 U256: UniqueSaturatedInto<
171 <F as Inspect<<T::AccountProvider as AccountProvider>::AccountId>>::Balance,
172 >,
173{
174 type LiquidityInfo = Option<Credit<<T::AccountProvider as AccountProvider>::AccountId, F>>;
176
177 fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, pallet_evm::Error<T>> {
178 pallet_evm::EVMFungibleAdapter::<F, FeeHandler>::withdraw_fee(who, fee)
179 }
180
181 fn can_withdraw(who: &H160, amount: U256) -> Result<(), pallet_evm::Error<T>> {
182 pallet_evm::EVMFungibleAdapter::<F, FeeHandler>::can_withdraw(who, amount)
183 }
184
185 fn correct_and_deposit_fee(
186 who: &H160,
187 corrected_fee: U256,
188 base_fee: U256,
189 already_withdrawn: Self::LiquidityInfo,
190 ) -> Self::LiquidityInfo {
191 <pallet_evm::EVMFungibleAdapter::<F, FeeHandler> as OnChargeEVMTransaction<T>>::correct_and_deposit_fee(
192 who,
193 corrected_fee,
194 base_fee,
195 already_withdrawn,
196 )
197 }
198
199 fn pay_priority_fee(tip: Self::LiquidityInfo) {
200 if let Some(tip) = tip {
201 TipHandler::on_unbalanceds(Some(tip).into_iter());
202 }
203 }
204}