Skip to content

Commit

Permalink
Merge pull request #795 from galacticcouncil/feat/evm-permit
Browse files Browse the repository at this point in the history
feat: evm permit
  • Loading branch information
mrq1911 authored Apr 29, 2024
2 parents a8a929d + 38723b9 commit 1106ca0
Show file tree
Hide file tree
Showing 193 changed files with 15,995 additions and 378 deletions.
318 changes: 272 additions & 46 deletions Cargo.lock

Large diffs are not rendered by default.

21 changes: 20 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,28 @@ members = [
'pallets/evm-accounts',
'pallets/dynamic-evm-fee',
'pallets/xyk-liquidity-mining',
'precompiles/call-permit',
]

resolver = "2"

[workspace.dependencies]
log = "0.4.20"
async-trait = "0.1"
futures = "0.3.25"
hex-literal = "0.4.1"
paste = "1.0.6"
slices = "0.2.0"
derive_more = "0.99"
affix = "0.1.2"
similar-asserts = "1.1.0"
impl-trait-for-tuples = "0.2.1"
environmental = {version = "1.1.2", default-features = false}
hex = {version = "0.4.3", default-features = false}
sha3 = {version = "0.10", default-features = false}
serde = {version = "1.0.101", default-features = false}
libsecp256k1 = {version = "0.7", default-features = false}
num_enum = {version = "0.5.3", default-features = false}
hydra-dx-math = { path = "math", default-features = false }
hydradx = { path = "node", default-features = false }
hydradx-traits = { path = "traits", default-features = false }
Expand Down Expand Up @@ -95,6 +110,9 @@ test-utils = { path = "utils/test-utils", default-features = false }

integration-tests = { path = "integration-tests", default-features = false }

pallet-evm-precompile-call-permit = { path ="precompiles/call-permit", default-features = false }
precompile-utils = { path ="precompiles/utils", default-features = false }

# Codec
codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false, features = ["derive"] }
scale-info = { version = "2.1.2", default-features = false, features = ["derive"] }
Expand Down Expand Up @@ -159,6 +177,7 @@ sc-tracing = { git = "https://github.com/paritytech/polkadot-sdk", rev = "c8d225
sc-transaction-pool = { git = "https://github.com/paritytech/polkadot-sdk", rev = "c8d2251cafadc108ba2f1f8a3208dc547ff38901", default-features = false }
sc-transaction-pool-api = { git = "https://github.com/paritytech/polkadot-sdk", rev = "c8d2251cafadc108ba2f1f8a3208dc547ff38901", default-features = false }
sc-sysinfo = { git = "https://github.com/paritytech/polkadot-sdk", rev = "c8d2251cafadc108ba2f1f8a3208dc547ff38901", default-features = false }
sp-weights = { git = "https://github.com/paritytech/polkadot-sdk", rev = "c8d2251cafadc108ba2f1f8a3208dc547ff38901", default-features = false }

# Substrate Pallets
pallet-aura = { git = "https://github.com/paritytech/polkadot-sdk", rev = "c8d2251cafadc108ba2f1f8a3208dc547ff38901", default-features = false }
Expand Down Expand Up @@ -584,4 +603,4 @@ westend-runtime = { git = "https://github.com/galacticcouncil/polkadot-sdk", rev

cumulus-client-pov-recovery = { git = "https://github.com/galacticcouncil/polkadot-sdk", rev = "062d92eae0f3bb9908faf2d4e241eef17368b9d3" }
cumulus-pallet-parachain-system-proc-macro = { git = "https://github.com/galacticcouncil/polkadot-sdk", rev = "062d92eae0f3bb9908faf2d4e241eef17368b9d3" }
cumulus-relay-chain-rpc-interface = { git = "https://github.com/galacticcouncil/polkadot-sdk", rev = "062d92eae0f3bb9908faf2d4e241eef17368b9d3" }
cumulus-relay-chain-rpc-interface = { git = "https://github.com/galacticcouncil/polkadot-sdk", rev = "062d92eae0f3bb9908faf2d4e241eef17368b9d3" }
11 changes: 9 additions & 2 deletions 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.20.3"
version = "1.21.0"
description = "Integration tests"
authors = ["GalacticCouncil"]
edition = "2021"
Expand Down Expand Up @@ -62,6 +62,9 @@ orml-xtokens = { workspace = true }
orml-xcm-support = { workspace = true }
orml-unknown-tokens = { workspace = true }

precompile-utils = { workspace = true }
pallet-evm-precompile-call-permit = { workspace = true }

# Evm
pallet-evm = { workspace = true }
fp-evm = { workspace = true }
Expand Down Expand Up @@ -132,6 +135,9 @@ pretty_assertions = "1.2.1"
pallet-relaychain-info = { workspace = true }
xcm-emulator = { workspace = true }
test-utils = { workspace = true }
libsecp256k1 = { workspace = true }


[features]
default = ["std"]
std = [
Expand Down Expand Up @@ -197,7 +203,8 @@ std = [
"hydradx-runtime/std",
"pallet-staking/std",
"scraper/std",
"pallet-dynamic-evm-fee/std"
"pallet-dynamic-evm-fee/std",
"precompile-utils/std",
]

# we don't include integration tests when benchmarking feature is enabled
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/src/dca.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3447,7 +3447,7 @@ pub fn init_stableswap_with_three_assets_having_different_decimals(
let mut added_liquidity: Vec<AssetAmount<<Runtime as pallet_stableswap::Config>::AssetId>> = vec![];

let mut asset_ids: Vec<<Runtime as pallet_stableswap::Config>::AssetId> = Vec::new();
let decimals_for_each_asset = vec![12u8, 6u8, 6u8];
let decimals_for_each_asset = [12u8, 6u8, 6u8];
for idx in 0u32..3 {
let name: Vec<u8> = idx.to_ne_bytes().to_vec();

Expand Down
181 changes: 22 additions & 159 deletions integration-tests/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,23 @@ use crate::{assert_balance, polkadot_test_net::*};
use fp_evm::{Context, Transfer};
use fp_rpc::runtime_decl_for_ethereum_runtime_rpc_api::EthereumRuntimeRPCApi;
use frame_support::storage::with_transaction;
use frame_support::traits::fungible::Mutate;
use frame_support::{assert_ok, dispatch::GetDispatchInfo, sp_runtime::codec::Encode, traits::Contains};
use frame_system::RawOrigin;
use hex_literal::hex;
use hydradx_runtime::evm::precompiles::DISPATCH_ADDR;
use hydradx_runtime::evm::ExtendedAddressMapping;
use hydradx_runtime::XYK;
use hydradx_runtime::{
evm::precompiles::{
addr,
handle::EvmDataWriter,
multicurrency::{Action, MultiCurrencyPrecompile},
Address, Bytes, EvmAddress, HydraDXPrecompiles,
},
AssetRegistry, Balances, CallFilter, Currencies, EVMAccounts, Omnipool, RuntimeCall, RuntimeOrigin, Tokens,
TransactionPause, EVM,
};
use hydradx_traits::router::{PoolType, Trade};
use hydradx_traits::AssetKind;
use hydradx_traits::Create;
use orml_traits::MultiCurrency;
Expand Down Expand Up @@ -1410,157 +1412,6 @@ fn compare_fee_in_eth_between_evm_and_native_omnipool_calls() {
})
}

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

Hydra::execute_with(|| {
let fee_currency = HDX;
let evm_address = EVMAccounts::evm_address(&Into::<AccountId>::into(ALICE));
assert_ok!(EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed(
ALICE.into()
)));

//Set up to idle state where the chain is not utilized at all
pallet_transaction_payment::pallet::NextFeeMultiplier::<hydradx_runtime::Runtime>::put(
hydradx_runtime::MinimumMultiplier::get(),
);

init_omnipool_with_oracle_for_block_10();

assert_ok!(hydradx_runtime::Currencies::update_balance(
hydradx_runtime::RuntimeOrigin::root(),
ALICE.into(),
HDX,
(10_000 * UNITS) as i128,
));
assert_ok!(hydradx_runtime::MultiTransactionPayment::set_currency(
hydradx_runtime::RuntimeOrigin::signed(ALICE.into()),
fee_currency,
));

// give alice evm addr seom weth to sell in omnipool
assert_ok!(hydradx_runtime::Currencies::update_balance(
hydradx_runtime::RuntimeOrigin::root(),
ALICE.into(),
DOT,
(10 * UNITS) as i128,
));

let treasury_currency_balance = Currencies::free_balance(fee_currency, &Treasury::account_id());
let alice_currency_balance = Currencies::free_balance(fee_currency, &AccountId::from(ALICE));

//Act
let omni_sell =
hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::<hydradx_runtime::Runtime>::sell {
asset_in: DOT,
asset_out: WETH,
amount: 10_000_000_000,
min_buy_amount: 0,
});

let gas_limit = 1_000_000;
let (gas_price, _) = hydradx_runtime::DynamicEvmFee::min_gas_price();

//Execute omnipool sell via EVM
assert_ok!(EVM::call(
hydradx_runtime::RuntimeOrigin::signed(ALICE.into()),
evm_address,
DISPATCH_ADDR,
omni_sell.encode(),
U256::from(0),
gas_limit,
gas_price * 10,
None,
Some(U256::zero()),
[].into(),
));

let new_treasury_currency_balance = Currencies::free_balance(fee_currency, &Treasury::account_id());
let new_alice_currency_balance = Currencies::free_balance(fee_currency, &AccountId::from(ALICE));
let evm_fee = alice_currency_balance - new_alice_currency_balance;
let treasury_evm_fee = new_treasury_currency_balance - treasury_currency_balance;
assert_eq!(treasury_evm_fee, evm_fee);

//Pre dispatch the native omnipool call - so withdrawing only the fees for the execution
let info = omni_sell.get_dispatch_info();
let len: usize = 146;
let pre = pallet_transaction_payment::ChargeTransactionPayment::<hydradx_runtime::Runtime>::from(0)
.pre_dispatch(&AccountId::from(ALICE), &omni_sell, &info, len);
assert_ok!(&pre);

let alice_currency_balance_pre_dispatch = Currencies::free_balance(fee_currency, &AccountId::from(ALICE));
let native_fee = new_alice_currency_balance - alice_currency_balance_pre_dispatch;
assert!(evm_fee > native_fee);

let fee_difference = evm_fee - native_fee;
assert!(fee_difference > 0);
let relative_fee_difference = FixedU128::from_rational(fee_difference, native_fee);
let tolerated_fee_difference = FixedU128::from_rational(20, 100);
// EVM fees should be not higher than 20%
assert!(relative_fee_difference < tolerated_fee_difference);
})
}

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

Hydra::execute_with(|| {
let evm_address = EVMAccounts::evm_address(&Into::<AccountId>::into(ALICE));
assert_ok!(EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed(
ALICE.into()
)));

//Set up to idle state where the chain is not utilized at all
pallet_transaction_payment::pallet::NextFeeMultiplier::<hydradx_runtime::Runtime>::put(
hydradx_runtime::MinimumMultiplier::get(),
);
assert_ok!(hydradx_runtime::Currencies::update_balance(
hydradx_runtime::RuntimeOrigin::root(),
ALICE.into(),
HDX,
100_000_000_000_000i128,
));

init_omnipool_with_oracle_for_block_10();
let treasury_hdx_balance = Currencies::free_balance(HDX, &Treasury::account_id());
let alice_hdx_balance = Currencies::free_balance(HDX, &AccountId::from(ALICE));
//Act
let omni_sell =
hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::<hydradx_runtime::Runtime>::sell {
asset_in: DOT,
asset_out: WETH,
amount: 10_000_000,
min_buy_amount: 0,
});

let gas_limit = 1000000;
let gas_price = hydradx_runtime::DynamicEvmFee::min_gas_price();

//Execute omnipool via EVM
assert_ok!(EVM::call(
hydradx_runtime::RuntimeOrigin::signed(ALICE.into()),
evm_address,
DISPATCH_ADDR,
omni_sell.encode(),
U256::from(0),
gas_limit,
gas_price.0 * 10,
None,
Some(U256::zero()),
[].into(),
));
//let alice_new_weth_balance = Tokens::free_balance(WETH, &AccountId::from(ALICE));
let alice_new_hdx_balance = Currencies::free_balance(HDX, &AccountId::from(ALICE));
let fee_amount = alice_hdx_balance - alice_new_hdx_balance;
assert!(fee_amount > 0);

let new_treasury_hdx_balance = Currencies::free_balance(HDX, &Treasury::account_id());
let treasury_hdx_diff = new_treasury_hdx_balance - treasury_hdx_balance;
assert_eq!(fee_amount, treasury_hdx_diff);
})
}
pub fn init_omnipool_with_oracle_for_block_10() {
init_omnipol();
hydradx_run_to_next_block();
Expand All @@ -1570,6 +1421,7 @@ pub fn init_omnipool_with_oracle_for_block_10() {
for _ in from..=to {
hydradx_run_to_next_block();
do_trade_to_populate_oracle(DOT, HDX, 1_000_000_000_000);
do_trade_to_populate_oracle(DAI, HDX, 1_000_000_000_000);
do_trade_to_populate_oracle(WETH, DOT, 1_000_000_000_000);
}
}
Expand Down Expand Up @@ -1600,14 +1452,13 @@ fn do_trade_to_populate_oracle(asset_1: AssetId, asset_2: AssetId, amount: Balan
));
}

use frame_support::traits::fungible::Mutate;
use hydradx_traits::router::{PoolType, Trade};

pub fn init_omnipol() {
let native_price = FixedU128::from_rational(29903049701668757, 73927734532192294158);
let dot_price = FixedU128::from_rational(103158291366950047, 4566210555614178);
let stable_price = FixedU128::from_inner(45_000_000_000);
let acc = hydradx_runtime::Omnipool::protocol_account();

let stable_amount = 50_000_000 * UNITS * 1_000_000;
let dot_amount: Balance = 4566210555614178u128;
let native_amount: Balance = 73927734532192294158u128;
let weth_amount: Balance = 1074271742496220564487u128;
Expand All @@ -1620,7 +1471,13 @@ pub fn init_omnipol() {
0
));
Balances::set_balance(&acc, native_amount);
assert_ok!(Tokens::set_balance(RawOrigin::Root.into(), acc, WETH, weth_amount, 0));
assert_ok!(Tokens::set_balance(
RawOrigin::Root.into(),
acc.clone(),
WETH,
weth_amount,
0
));
assert_ok!(hydradx_runtime::Omnipool::add_token(
hydradx_runtime::RuntimeOrigin::root(),
HDX,
Expand All @@ -1644,6 +1501,15 @@ pub fn init_omnipol() {
AccountId::from(ALICE),
));

assert_ok!(Tokens::set_balance(RawOrigin::Root.into(), acc, DAI, stable_amount, 0));
assert_ok!(hydradx_runtime::Omnipool::add_token(
hydradx_runtime::RuntimeOrigin::root(),
DAI,
stable_price,
Permill::from_percent(100),
AccountId::from(ALICE),
));

assert_ok!(Balances::force_set_balance(
RawOrigin::Root.into(),
hydradx_runtime::Treasury::account_id(),
Expand All @@ -1652,9 +1518,6 @@ pub fn init_omnipol() {
}

// TODO: test that we charge approximatelly same fee on evm as with extrinsics directly

pub const DISPATCH_ADDR: H160 = addr(1025);

pub fn gas_price() -> U256 {
U256::from(hydradx_runtime::evm::DEFAULT_BASE_FEE_PER_GAS)
}
Expand Down
Loading

0 comments on commit 1106ca0

Please sign in to comment.