Skip to content

Commit

Permalink
Merge pull request #790 from galacticcouncil/evm_payment_asset
Browse files Browse the repository at this point in the history
feat: set payment asset of EVM accounts to WETH
  • Loading branch information
mrq1911 authored Mar 18, 2024
2 parents 36f6b5e + 2c478b9 commit 43ec430
Show file tree
Hide file tree
Showing 21 changed files with 355 additions and 130 deletions.
12 changes: 7 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "runtime-integration-tests"
version = "1.19.8"
version = "1.19.9"
description = "Integration tests"
authors = ["GalacticCouncil"]
edition = "2021"
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/src/insufficient_assets_ed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ fn sender_should_pay_ed_only_when_dest_didnt_pay_yet() {
}

#[test]
fn dest_should_pay_ed_only_once_when_insufficient_asset_was_depsitted() {
fn dest_should_pay_ed_only_once_when_insufficient_asset_was_deposited() {
TestNet::reset();
Hydra::execute_with(|| {
let sht1: AssetId = register_external_asset(0_u128);
Expand Down
37 changes: 37 additions & 0 deletions integration-tests/src/non_native_fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use primitives::Price;

use hydradx_adapters::OraclePriceProvider;
use hydradx_traits::{
evm::InspectEvmAccounts,
pools::SpotPriceProvider,
router::{AssetPair, RouteProvider},
OraclePeriod, PriceOracle,
Expand Down Expand Up @@ -117,6 +118,42 @@ fn fee_currency_on_account_lifecycle() {
});
}

#[test]
fn fee_currency_on_evm_account_lifecycle() {
TestNet::reset();

Hydra::execute_with(|| {
assert_eq!(MultiTransactionPayment::get_currency(AccountId::from(HITCHHIKER)), None);

let evm_address = hydradx_runtime::EVMAccounts::evm_address(&Into::<AccountId>::into(HITCHHIKER));
let truncated_account: AccountId = hydradx_runtime::EVMAccounts::truncated_account_id(evm_address);

// ------------ set on create ------------
assert_ok!(Currencies::transfer(
RuntimeOrigin::signed(BOB.into()),
truncated_account.clone(),
DAI,
50_000_000_000_000,
));

assert_eq!(Tokens::free_balance(DAI, &truncated_account), 50_000_000_000_000);
assert_eq!(
MultiTransactionPayment::get_currency(truncated_account.clone()),
Some(WETH)
);

// ------------ remove on delete ------------
assert_ok!(Tokens::transfer_all(
RuntimeOrigin::signed(truncated_account.clone()),
BOB.into(),
DAI,
false,
));

assert_eq!(MultiTransactionPayment::get_currency(truncated_account), None);
});
}

#[test]
fn pepe_is_not_registered() {
TestNet::reset();
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/src/polkadot_test_net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
pub use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
use hex_literal::hex;
use hydradx_runtime::{evm::WETH_ASSET_LOCATION, Referrals, RuntimeOrigin};
use hydradx_traits::registry::Mutate;
pub use hydradx_traits::{evm::InspectEvmAccounts, registry::Mutate};
use pallet_referrals::{FeeDistribution, Level};
pub use polkadot_primitives::v5::{BlockNumber, MAX_CODE_SIZE, MAX_POV_SIZE};
use polkadot_runtime_parachains::configuration::HostConfiguration;
Expand Down
3 changes: 2 additions & 1 deletion pallets/evm-accounts/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pallet-evm-accounts"
version = "1.1.0"
version = "1.1.1"
authors = ['GalacticCouncil']
edition = "2021"
license = "Apache-2.0"
Expand All @@ -13,6 +13,7 @@ readme = "README.md"
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
hydradx-traits = { workspace = true }
# parity
scale-info = { version = "2.3.1", default-features = false, features = ["derive"] }
codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "3.4.0" }
Expand Down
24 changes: 16 additions & 8 deletions pallets/evm-accounts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@

use frame_support::ensure;
use frame_support::pallet_prelude::{DispatchResult, Get};
use hydradx_traits::evm::InspectEvmAccounts;
use sp_core::{
crypto::{AccountId32, ByteArray},
H160, U256,
Expand Down Expand Up @@ -262,26 +263,32 @@ pub mod pallet {
}
}

impl<T: Config> Pallet<T>
impl<T: Config> InspectEvmAccounts<T::AccountId, EvmAddress> for Pallet<T>
where
T::AccountId: frame_support::traits::IsType<AccountId32>,
T::AccountId: AsRef<[u8; 32]> + frame_support::traits::IsType<AccountId32>,
{
/// get the EVM address from the substrate address.
pub fn evm_address(account_id: &impl AsRef<[u8; 32]>) -> EvmAddress {
/// Returns `True` if the account is EVM truncated account.
fn is_evm_account(account_id: T::AccountId) -> bool {
let account_ref = account_id.as_ref();
&account_ref[0..4] == b"ETH\0" && account_ref[24..32] == [0u8; 8]
}

/// Get the EVM address from the substrate address.
fn evm_address(account_id: &impl AsRef<[u8; 32]>) -> EvmAddress {
let acc = account_id.as_ref();
EvmAddress::from_slice(&acc[..20])
}

/// Get the truncated address from the EVM address.
pub fn truncated_account_id(evm_address: EvmAddress) -> T::AccountId {
fn truncated_account_id(evm_address: EvmAddress) -> T::AccountId {
let mut data: [u8; 32] = [0u8; 32];
data[0..4].copy_from_slice(b"ETH\0");
data[4..24].copy_from_slice(&evm_address[..]);
AccountId32::from(data).into()
}

/// Return the Substrate address bound to the EVM account. If not bound, returns `None`.
pub fn bound_account_id(evm_address: EvmAddress) -> Option<T::AccountId> {
fn bound_account_id(evm_address: EvmAddress) -> Option<T::AccountId> {
let Some(last_12_bytes) = AccountExtension::<T>::get(evm_address) else {
return None;
};
Expand All @@ -293,11 +300,12 @@ where

/// Get the Substrate address from the EVM address.
/// Returns the truncated version of the address if the address wasn't bind.
pub fn account_id(evm_address: EvmAddress) -> T::AccountId {
fn account_id(evm_address: EvmAddress) -> T::AccountId {
Self::bound_account_id(evm_address).unwrap_or_else(|| Self::truncated_account_id(evm_address))
}

pub fn can_deploy_contracts(evm_address: EvmAddress) -> bool {
/// Returns `True` if the address is allowed to deploy smart contracts.
fn can_deploy_contracts(evm_address: EvmAddress) -> bool {
ContractDeployer::<T>::contains_key(evm_address)
}
}
3 changes: 2 additions & 1 deletion pallets/transaction-multi-payment/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pallet-transaction-multi-payment"
version = "9.3.1"
version = "9.4.0"
description = "Transaction multi currency payment support module"
authors = ["GalacticCoucil"]
edition = "2021"
Expand Down Expand Up @@ -37,6 +37,7 @@ pallet-evm = { workspace = true, optional = true }
pallet-currencies = { workspace = true }
orml-tokens = { workspace = true, features=["std"] }
pallet-balances = { workspace = true, features=["std"] }
pallet-evm-accounts = { workspace = true, features = ["std"] }
sp-io = { workspace = true }
test-utils = { workspace = true }

Expand Down
88 changes: 69 additions & 19 deletions pallets/transaction-multi-payment/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,29 @@ mod mock;
mod tests;
mod traits;

use frame_support::traits::Contains;
use frame_support::{dispatch::DispatchResult, ensure, traits::Get, weights::Weight};
pub use crate::traits::*;
use frame_support::traits::{Contains, IsSubType};
use frame_support::{
dispatch::DispatchResult,
ensure,
sp_runtime::{
traits::{DispatchInfoOf, One, PostDispatchInfoOf, Saturating, Zero},
transaction_validity::{InvalidTransaction, TransactionValidityError},
FixedPointNumber, FixedPointOperand, FixedU128,
},
traits::Get,
weights::Weight,
};
use frame_system::{ensure_signed, pallet_prelude::BlockNumberFor};
use hydra_dx_math::ema::EmaPrice;
use sp_runtime::{
traits::{DispatchInfoOf, One, PostDispatchInfoOf, Saturating, Zero},
transaction_validity::{InvalidTransaction, TransactionValidityError},
FixedU128,
use hydradx_traits::{
evm::InspectEvmAccounts,
router::{AssetPair, RouteProvider},
AccountFeeCurrency, NativePriceOracle, OraclePeriod, PriceOracle,
};
use sp_std::prelude::*;

use pallet_transaction_payment::OnChargeTransaction;
use sp_std::marker::PhantomData;

use frame_support::sp_runtime::FixedPointNumber;
use frame_support::sp_runtime::FixedPointOperand;
use hydradx_traits::{AccountFeeCurrency, NativePriceOracle};
use orml_traits::{GetByKey, Happened, MultiCurrency};

pub use crate::traits::*;
use frame_support::traits::IsSubType;
use hydradx_traits::router::{AssetPair, RouteProvider};
use hydradx_traits::{OraclePeriod, PriceOracle};
use pallet_transaction_payment::OnChargeTransaction;
use sp_std::{marker::PhantomData, prelude::*};

type AssetIdOf<T> = <<T as Config>::Currencies as MultiCurrency<<T as frame_system::Config>::AccountId>>::CurrencyId;
type BalanceOf<T> = <<T as Config>::Currencies as MultiCurrency<<T as frame_system::Config>::AccountId>>::Balance;
Expand Down Expand Up @@ -123,6 +123,13 @@ pub mod pallet {
/// Native Asset
#[pallet::constant]
type NativeAssetId: Get<AssetIdOf<Self>>;

/// EVM Asset
#[pallet::constant]
type EvmAssetId: Get<AssetIdOf<Self>>;

/// EVM Accounts info
type InspectEvmAccounts: InspectEvmAccounts<Self::AccountId, sp_core::H160>;
}

#[pallet::event]
Expand Down Expand Up @@ -176,6 +183,9 @@ pub mod pallet {

/// Math overflow
Overflow,

/// It is not allowed to change payment currency of an EVM account.
EvmAccountNotAllowed,
}

/// Account currency map
Expand Down Expand Up @@ -226,12 +236,19 @@ pub mod pallet {
///
/// When currency is set, fixed fee is withdrawn from the account to pay for the currency change
///
/// EVM accounts are now allowed to change thier payment currency.
///
/// Emits `CurrencySet` event when successful.
#[pallet::call_index(0)]
#[pallet::weight(<T as Config>::WeightInfo::set_currency())]
pub fn set_currency(origin: OriginFor<T>, currency: AssetIdOf<T>) -> DispatchResult {
let who = ensure_signed(origin)?;

ensure!(
!T::InspectEvmAccounts::is_evm_account(who.clone()),
Error::<T>::EvmAccountNotAllowed
);

ensure!(
currency == T::NativeAssetId::get() || AcceptedCurrencies::<T>::contains_key(currency),
Error::<T>::UnsupportedCurrency
Expand Down Expand Up @@ -297,6 +314,33 @@ pub mod pallet {
Ok(())
})
}

/// Reset currency of the specified account to HDX.
/// If the account is EVM account, the payment currency is reset to WETH.
/// Only selected members can perform this action.
///
/// Emits `CurrencySet` when successful.
#[pallet::call_index(3)]
#[pallet::weight(<T as Config>::WeightInfo::reset_payment_currency())]
pub fn reset_payment_currency(origin: OriginFor<T>, account_id: T::AccountId) -> DispatchResult {
T::AcceptedCurrencyOrigin::ensure_origin(origin)?;

let currency = if T::InspectEvmAccounts::is_evm_account(account_id.clone()) {
let currency = T::EvmAssetId::get();
AccountCurrencyMap::<T>::insert(account_id.clone(), currency);
currency
} else {
AccountCurrencyMap::<T>::remove(account_id.clone());
T::NativeAssetId::get()
};

Self::deposit_event(Event::CurrencySet {
account_id,
asset_id: currency,
});

Ok(())
}
}
}

Expand Down Expand Up @@ -478,6 +522,12 @@ impl<T: Config> NativePriceOracle<AssetIdOf<T>, Price> for Pallet<T> {
pub struct AddTxAssetOnAccount<T>(PhantomData<T>);
impl<T: Config> Happened<(T::AccountId, AssetIdOf<T>)> for AddTxAssetOnAccount<T> {
fn happened((who, currency): &(T::AccountId, AssetIdOf<T>)) {
// all new EVM accounts have WETH set as their payment currency
if T::InspectEvmAccounts::is_evm_account(who.clone()) {
AccountCurrencyMap::<T>::insert(who, T::EvmAssetId::get());
return;
}

if !AccountCurrencyMap::<T>::contains_key(who)
&& AcceptedCurrencies::<T>::contains_key(currency)
&& T::Currencies::total_balance(T::NativeAssetId::get(), who).is_zero()
Expand Down
Loading

0 comments on commit 43ec430

Please sign in to comment.