From 88aa8910a1a425ba00513e783cabda388d76a5f5 Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 12 Jan 2024 15:05:31 +0100 Subject: [PATCH 01/64] add ddos scripts --- scripts/init-testnet/ddos/ddos_init.ts | 158 +++++++++++++++++++++++++ scripts/init-testnet/ddos/ddos_run.ts | 123 +++++++++++++++++++ 2 files changed, 281 insertions(+) create mode 100644 scripts/init-testnet/ddos/ddos_init.ts create mode 100644 scripts/init-testnet/ddos/ddos_run.ts diff --git a/scripts/init-testnet/ddos/ddos_init.ts b/scripts/init-testnet/ddos/ddos_init.ts new file mode 100644 index 000000000..912a8b493 --- /dev/null +++ b/scripts/init-testnet/ddos/ddos_init.ts @@ -0,0 +1,158 @@ +// Required imports +const { ApiPromise, WsProvider } = require('@polkadot/api'); +const { hexToU8a } = require('@polkadot/util'); + +const { Keyring } = require('@polkadot/keyring'); + +async function main () { + // Initialise the provider to connect to the local node + //const provider = new WsProvider('wss://rpc.nice.hydration.cloud'); + const provider = new WsProvider('ws://127.0.0.1:9988'); + + // Create the API and wait until ready + const api = await ApiPromise.create({ provider }); + + // Retrieve the chain & node information information via rpc calls + const [chain, nodeName, nodeVersion] = await Promise.all([ + api.rpc.system.chain(), + api.rpc.system.name(), + api.rpc.system.version() + ]); + + console.log(`You are connected to chain ${chain} using ${nodeName} v${nodeVersion}`); + + const keyring = new Keyring({ type: 'sr25519' }); + const alice = keyring.addFromUri('//Alice'); + + let transactions = []; + assetRegistry(api, transactions); + mintForAlice(api, transactions); + mintUsersWithHDX(api, transactions); + initOmnipool(api, transactions) + + let batch = api.tx.utility.batchAll(transactions); + await api.tx.preimage.notePreimage(batch.method.toHex()).signAndSend(alice); +} + +main().catch(console.error).finally(() => process.exit()); + +function mintForTreasuryDca(api, txs) { + let treasury = "7KQx4f7yU3hqZHfvDVnSfe6mpgAT8Pxyr67LXHV6nsbZo3Tm"; + //weth + txs.push( + api.tx.currencies.updateBalance(treasury, 5, "5000000000000000") + ); + +} + +function mintForAlice(api, txs) { + let alice = "7NPoMQbiA6trJKkjB35uk96MeJD4PGWkLQLH7k7hXEkZpiba"; + txs.push( + api.tx.currencies.updateBalance(alice, 0, "5000000000000000000000000000") + ); + + txs.push(api.tx.currencies.updateBalance(alice, 1, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 2, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 3, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 4, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 5, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 6, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 7, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 8, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 9, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 10, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 20, "5000000000000000000")); +} + +function mintUsersWithHDX(api, txs) { + const keyring = new Keyring({ type: 'sr25519' }); + const user1 = keyring.addFromUri('//User1'); + const user2 = keyring.addFromUri('//User2'); + const user3 = keyring.addFromUri('//User3'); + const user4 = keyring.addFromUri('//User4'); + const user5 = keyring.addFromUri('//User5'); + const user6 = keyring.addFromUri('//User6'); + const user7 = keyring.addFromUri('//User7'); + const user8 = keyring.addFromUri('//User8'); + const user9 = keyring.addFromUri('//User9'); + const user10 = keyring.addFromUri('//User10'); + + txs.push(api.tx.currencies.updateBalance(user1.publicKey, 0, "5000000000000000000000000000")); + txs.push(api.tx.currencies.updateBalance(user2.publicKey, 0, "5000000000000000000000000000")); + txs.push(api.tx.currencies.updateBalance(user3.publicKey, 0, "5000000000000000000000000000")); + txs.push(api.tx.currencies.updateBalance(user4.publicKey, 0, "5000000000000000000000000000")); + txs.push(api.tx.currencies.updateBalance(user5.publicKey, 0, "5000000000000000000000000000")); + txs.push(api.tx.currencies.updateBalance(user6.publicKey, 0, "5000000000000000000000000000")); + txs.push(api.tx.currencies.updateBalance(user7.publicKey, 0, "5000000000000000000000000000")); + txs.push(api.tx.currencies.updateBalance(user8.publicKey, 0, "5000000000000000000000000000")); + txs.push(api.tx.currencies.updateBalance(user9.publicKey, 0, "5000000000000000000000000000")); + txs.push(api.tx.currencies.updateBalance(user10.publicKey, 0, "5000000000000000000000000000")); +} + +function assetRegistry(api, txs) { + const assets = require('./assets.json'); + let keys = Object.keys(assets); + + for (let i = 0, l = keys.length; i < l; i++) { + let k = keys[i]; + let a = assets[k]; + let tx; + + if (k == "0") { + tx = api.tx.assetRegistry.setMetadata(k, a.metadata.symbol, a.metadata.decimals); + txs.push(tx); + + continue; + } + + if (k == "1" || k == "2") { + let aType = {}; + aType[a.asset.assetType] = 0; + + tx = api.tx.assetRegistry.update(k, a.asset.name, aType, 100, null); + txs.push(tx); + + tx = api.tx.assetRegistry.setMetadata(k, a.metadata.symbol, a.metadata.decimals); + txs.push(tx); + continue; + } + + let aType = {}; + aType[a.asset.assetType] = 0; + + a.metadata.decimals = Number(a.metadata.decimals); + + tx = api.tx.assetRegistry.register(a.asset.name, aType, 100, k, a.metadata, null, null); + txs.push(tx); + }; + + return txs; +} + +function initOmnipool(api, txs) { + let omniAccount = "7L53bUTBbfuj14UpdCNPwmgzzHSsrsTWBHX5pys32mVWM3C1"; + //hdx + txs.push( + api.tx.currencies.updateBalance(omniAccount, 0, "936329588000000000") + ); + + //dai + txs.push( + api.tx.currencies.updateBalance(omniAccount, 2, "50000000000000000000000") + ); + + txs.push( + api.tx.currencies.updateBalance(omniAccount, 5, "936329588000000000") + ); + + txs.push( + api.tx.omnipool.addToken(0, "1201500000000000", 1000000, omniAccount) + ); + txs.push( + api.tx.omnipool.addToken(2, "1501500000000000", 1000000, omniAccount) + ); + + txs.push( + api.tx.omnipool.addToken(5, "1701500000000000", 1000000, omniAccount) + ); +} \ No newline at end of file diff --git a/scripts/init-testnet/ddos/ddos_run.ts b/scripts/init-testnet/ddos/ddos_run.ts new file mode 100644 index 000000000..aabb40f8a --- /dev/null +++ b/scripts/init-testnet/ddos/ddos_run.ts @@ -0,0 +1,123 @@ +// Required imports +const { ApiPromise, WsProvider } = require('@polkadot/api'); +const { hexToU8a } = require('@polkadot/util'); + +const { Keyring } = require('@polkadot/keyring'); + +async function main () { + // Initialise the provider to connect to the local node + //const provider = new WsProvider('wss://rpc.nice.hydration.cloud'); + const provider = new WsProvider('ws://127.0.0.1:9988'); + + // Create the API and wait until ready + const api = await ApiPromise.create({ provider }); + + // Retrieve the chain & node information information via rpc calls + const [chain, nodeName, nodeVersion] = await Promise.all([ + api.rpc.system.chain(), + api.rpc.system.name(), + api.rpc.system.version() + ]); + + console.log(`You are connected to chain ${chain} using ${nodeName} v${nodeVersion}`); + + const keyring = new Keyring({ type: 'sr25519' }); + const alice = keyring.addFromUri('//Alice'); + + let balance = await api.query.system.account(alice.publicKey); + console.log(`Alice's HDX balance before DDOS ${balance.data.free}`); + + const blockNumber = await api.rpc.chain.getBlock(); + + await createDcaSchedules(api, alice, blockNumber.block.header.number); + + let balance_after = await api.query.system.account(alice.publicKey); + console.log(`Alice's HDX balance after DDOS ${balance_after.data.free}`); + + let balance_diff = balance.data.free - balance_after.data.free; + + console.log(`Alice's spent balance ${balance_diff}`); + +} + +main().catch(console.error).finally(() => process.exit()); + +async function createDcaSchedules(api, user, block) { + let counter = 0; + let prev_block = block; + let prev_balance = await api.query.system.account(user.publicKey); + + while (1) { + const blockInfo = await api.rpc.chain.getBlock(); + const blockNumber = blockInfo.block.header.number; + + //Change this `ddos_run_duration` variable to define how long (in blocks) the DDOS should take + let ddos_run_duration = 1000; + let block_spent = blockNumber - block; + if (block_spent == ddos_run_duration) { + console.log(`The specified blocktime ${block_spent} passed`); + break; + } + + //If there is a new block + if (!(Math.abs(blockNumber - prev_block) < Number.EPSILON)) { + ///Change this `dcas_per_block` variable to reach different extrinsic weight utilization + ///10 (10%) + ///20 (20%) + ///28 (30%) + ///38 (40%) + ///48 (50%) + ///56 (60%) + ///64 (70%) + ///72 (80%) + ///85 (90%) + ///100 (100%) + let dcas_per_block = 100; + for (let i = 0; i < dcas_per_block; i++) { + let user_pub_key = user.publicKey; + const nonce = await api.rpc.system.accountNextIndex(user_pub_key); + const tip = 1; + + await createDca(user_pub_key, nonce, tip); + } + + //Print out block feeresult + let balance = await api.query.system.account(user.publicKey); + let balance_diff = prev_balance.data.free - balance.data.free; + const blockWeight = await api.query.system.blockWeight(); + + console.log(`Fee spent in block ${blockNumber} with weight ${blockWeight.normal.refTime}: ${balance_diff} HDX`); + + prev_block = blockNumber; + prev_balance = balance; + } + } + + async function createDca(user_pub_key, nonce, tip) { + try { + await api.tx.dca + .schedule( + { + owner: user_pub_key, + period: 1, + totalAmount: 1000000000000000, + maxRetries: null, + stabilityThreshold: null, + slippage: null, + order: { + Sell: { + assetIn: 5, + assetOut: 2, + amountIn: 100000000000000, + minAmountOut: 0, + route: null + } + } + }, + null) + .signAndSend(user, { nonce, tip }); + } catch (error) { + console.log("Error while sending DCA - Sent transaction counter when signing fails: ", counter); + } + } +} \ No newline at end of file From 882ce5ad30e94d104d106c5dd592cde95199af42 Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 12 Jan 2024 15:28:50 +0100 Subject: [PATCH 02/64] fix init script to read the assets from good directory --- scripts/init-testnet/ddos/ddos_init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/init-testnet/ddos/ddos_init.ts b/scripts/init-testnet/ddos/ddos_init.ts index 912a8b493..bb4569fd8 100644 --- a/scripts/init-testnet/ddos/ddos_init.ts +++ b/scripts/init-testnet/ddos/ddos_init.ts @@ -90,7 +90,7 @@ function mintUsersWithHDX(api, txs) { } function assetRegistry(api, txs) { - const assets = require('./assets.json'); + const assets = require('../assets.json'); let keys = Object.keys(assets); for (let i = 0, l = keys.length; i < l; i++) { From 7bdc1f20e878de337d1a8872ed0028a6adf179e6 Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 12 Jan 2024 15:42:39 +0100 Subject: [PATCH 03/64] remove invalid tx from init --- scripts/init-testnet/ddos/ddos_init.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/init-testnet/ddos/ddos_init.ts b/scripts/init-testnet/ddos/ddos_init.ts index bb4569fd8..5e81d04f8 100644 --- a/scripts/init-testnet/ddos/ddos_init.ts +++ b/scripts/init-testnet/ddos/ddos_init.ts @@ -61,7 +61,6 @@ function mintForAlice(api, txs) { txs.push(api.tx.currencies.updateBalance(alice, 8, "5000000000000000000")); txs.push(api.tx.currencies.updateBalance(alice, 9, "5000000000000000000")); txs.push(api.tx.currencies.updateBalance(alice, 10, "5000000000000000000")); - txs.push(api.tx.currencies.updateBalance(alice, 20, "5000000000000000000")); } function mintUsersWithHDX(api, txs) { From 87ff9514e2db7d6baed419c309b2165f42d0c32d Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 12 Jan 2024 15:46:10 +0100 Subject: [PATCH 04/64] fix print out --- scripts/init-testnet/ddos/ddos_run.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/init-testnet/ddos/ddos_run.ts b/scripts/init-testnet/ddos/ddos_run.ts index aabb40f8a..7a5689e61 100644 --- a/scripts/init-testnet/ddos/ddos_run.ts +++ b/scripts/init-testnet/ddos/ddos_run.ts @@ -86,7 +86,7 @@ async function createDcaSchedules(api, user, block) { let balance_diff = prev_balance.data.free - balance.data.free; const blockWeight = await api.query.system.blockWeight(); - console.log(`Fee spent in block ${blockNumber} with weight ${blockWeight.normal.refTime}: ${balance_diff} HDX`); + console.log(`${balance_diff} HDX fee spent in block ${blockNumber} with weight ${blockWeight.normal.refTime}`); prev_block = blockNumber; prev_balance = balance; From 8f741806383fea325aeed040f350d60d325908f6 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 18 Jan 2024 12:03:32 +0100 Subject: [PATCH 05/64] improve logging for ddos tx script --- scripts/init-testnet/ddos/ddos_tx.ts | 135 +++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 scripts/init-testnet/ddos/ddos_tx.ts diff --git a/scripts/init-testnet/ddos/ddos_tx.ts b/scripts/init-testnet/ddos/ddos_tx.ts new file mode 100644 index 000000000..3153dd8b1 --- /dev/null +++ b/scripts/init-testnet/ddos/ddos_tx.ts @@ -0,0 +1,135 @@ +// Required imports +const { ApiPromise, WsProvider } = require('@polkadot/api'); +const { hexToU8a } = require('@polkadot/util'); + +const { Keyring } = require('@polkadot/keyring'); + +async function main () { + // Initialise the provider to connect to the local node + //const provider = new WsProvider('wss://rpc.nice.hydration.cloud'); + const provider = new WsProvider('ws://127.0.0.1:9988'); + + // Create the API and wait until ready + const api = await ApiPromise.create({ provider }); + + // Retrieve the chain & node information information via rpc calls + const [chain, nodeName, nodeVersion] = await Promise.all([ + api.rpc.system.chain(), + api.rpc.system.name(), + api.rpc.system.version() + ]); + + console.log(`You are connected to chain ${chain} using ${nodeName} v${nodeVersion}`); + + const keyring = new Keyring({ type: 'sr25519' }); + const alice = keyring.addFromUri('//Alice'); + + let balance = await api.query.system.account(alice.publicKey); + console.log(`Alice's HDX balance before DDOS ${balance.data.free}`); + + const blockNumber = await api.rpc.chain.getBlock(); + + let alice_pub_key = alice.publicKey; + + await doOmnipoolSells(api, alice, blockNumber.block.header.number); + + let balance_after = await api.query.system.account(alice.publicKey); + console.log(`Alice's HDX balance after DDOS ${balance_after.data.free}`); + + let balance_diff = balance.data.free - balance_after.data.free; + + console.log(`Alice's spent balance ${balance_diff}`); + +} + +main().catch(console.error).finally(() => process.exit()); + +async function doOmnipoolSells(api, user, block) { + const start = Date.now(); + + let counter = 0; + let prev_block = block; + let prev_balance = await api.query.system.account(user.publicKey); + let multiplier = await api.query.transactionPayment.nextFeeMultiplier(); + + + while (1) { + const blockInfo = await api.rpc.chain.getBlock(); + const blockNumber = blockInfo.block.header.number; + + //Change this `ddos_run_duration` variable to define how long (in blocks) the DDOS should take + let ddos_run_duration = 1000; + let block_spent = blockNumber - block; + if (block_spent == ddos_run_duration) { + console.log(`The specified blocktime ${block_spent} passed`); + break; + } + + //If there is a new block + if (!(Math.abs(blockNumber - prev_block) < Number.EPSILON)) { + let sells_per_block = 1; + for (let i = 0; i < sells_per_block; i++) { + let user_pub_key = user.publicKey; + const nonce = await api.rpc.system.accountNextIndex(user_pub_key); + const tip = 1; + + await omniSell(api, user, nonce, tip) + } + + //Print out block feeresult + let balance = await api.query.system.account(user.publicKey); + let balance_diff = prev_balance.data.free - balance.data.free; + const blockWeight = await api.query.system.blockWeight(); + + let fee_per_tx = balance_diff / sells_per_block/1000000000000; + + const info = await api.tx.omnipool.sell(5, 2, 100000000000000, 0).paymentInfo(user); + const minute_passed = Math.round((Date.now() - start)/1000/60); + let multiplier = await api.query.transactionPayment.nextFeeMultiplier(); + + console.log(`Fee: ${info.partialFee.toHuman()} with multiplier ${multiplier}| Analyses: ${minute_passed} mins - ${balance_diff} HDX fee (${fee_per_tx} per tx) spent in block ${blockNumber} with weight ${blockWeight.normal.refTime}`); + + prev_block = blockNumber; + prev_balance = balance; + } + } + +async function createDca(user_pub_key, nonce, tip) { + try { + await api.tx.dca + .schedule( + { + owner: user_pub_key, + period: 1, + totalAmount: 1000000000000000, + maxRetries: null, + stabilityThreshold: null, + slippage: null, + order: { + Sell: { + assetIn: 5, + assetOut: 2, + amountIn: 100000000000000, + minAmountOut: 0, + route: null + } + } + }, + null) + .signAndSend(user, { nonce, tip }); + } catch (error) { + console.log("Error while sending DCA - Sent transaction counter when signing fails: ", counter); + } + } +} + + +async function omniSell(api, user, nonce, tip) { + try { + await api.tx.omnipool + .sell(5, 2, 100000000000000, 0) + .signAndSend(user, { nonce, tip }); + } catch (error) { + console.log("Error while sending DCA - Sent transaction counter when signing fails: ", error); + } +} \ No newline at end of file From 37f1dee6f0a6132a7cb8db193116fcfbc0aa37a8 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 18 Jan 2024 12:07:24 +0100 Subject: [PATCH 06/64] add tests for fees --- integration-tests/src/fee_calculation.rs | 387 +++++++++++++++++++++++ integration-tests/src/lib.rs | 2 + integration-tests/src/oracle.rs | 1 + 3 files changed, 390 insertions(+) create mode 100644 integration-tests/src/fee_calculation.rs diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs new file mode 100644 index 000000000..d760f8f20 --- /dev/null +++ b/integration-tests/src/fee_calculation.rs @@ -0,0 +1,387 @@ +#![cfg(test)] + +use crate::{oracle::hydradx_run_to_block, polkadot_test_net::*}; +use frame_support::assert_ok; +use frame_support::dispatch::GetDispatchInfo; +use frame_support::pallet_prelude::Weight; +use frame_support::weights::WeightToFee as WeightToFeeTrait; +use hydradx_runtime::Runtime; +use hydradx_runtime::TransactionPayment; +use hydradx_runtime::WeightToFee; +use pallet_dynamic_fees::types::FeeEntry; +use pallet_omnipool::traits::OmnipoolHooks; +use pallet_omnipool::WeightInfo; +use primitives::AssetId; +use sp_core::Encode; +use sp_runtime::{FixedU128, Permill}; +use xcm_emulator::TestExt; +const DOT_UNITS: u128 = 10_000_000_000; +const BTC_UNITS: u128 = 10_000_000; +const ETH_UNITS: u128 = 1_000_000_000_000_000_000; + +//TODO: clean up in this test file + +///original fee - 1.560005867338 +///1 cent per swap, we don't want to be more expensive +///300 blocks to reach the max +///30k per hour +use frame_support::dispatch::DispatchInfo; + +#[test] +fn fee_with_min_multiplier() { + TestNet::reset(); + Hydra::execute_with(|| { + init_omnipool(); + init_oracle(); + hydradx_run_to_block(2); + + assert_ok!(hydradx_runtime::MultiTransactionPayment::set_currency( + hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), + HDX, + )); + + let call = pallet_omnipool::Call::::sell { + asset_in: HDX, + asset_out: DOT, + amount: UNITS, + min_buy_amount: 0, + }; + + let info = call.get_dispatch_info(); + + /*pallet_transaction_payment::pallet::NextFeeMultiplier::::put( + hydradx_runtime::MinimumMultiplier::get(), + );*/ + + let multiplier = pallet_transaction_payment::pallet::NextFeeMultiplier::::get(); + //assert_eq!(multiplier, 1.into()); + + let rust_encoded_len = call.encoded_size() as u32; + let rust_encoded_fees = TransactionPayment::compute_fee(rust_encoded_len, &info, 0); //638733816906 + assert_eq!(rust_encoded_fees / 4, 1596834542266); + + /*let post = PostDispatchInfo { + actual_weight: Some(Weight::from_ref_time(55)), //520000033053 + pays_fee: Default::default(), + }; + let rust_encoded_fees = TransactionPayment::compute_actual_fee(rust_encoded_len, &info, &post, 0);*/ + hydradx_run_to_block(3); + hydradx_run_to_block(4); + hydradx_run_to_block(5); + hydradx_run_to_block(6); + }); +} + +#[test] +fn fee_with_max_multiplier() { + TestNet::reset(); + + Hydra::execute_with(|| { + init_omnipool(); + init_oracle(); + hydradx_run_to_block(10); + + assert_ok!(hydradx_runtime::MultiTransactionPayment::set_currency( + hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), + HDX, + )); + + let call = hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { + asset_in: DOT, + asset_out: 2, + amount: UNITS, + min_buy_amount: 0, + }); + + let info = call.get_dispatch_info(); + + pallet_transaction_payment::pallet::NextFeeMultiplier::::put( + hydradx_runtime::MaximumMultiplier::get(), + ); + + let rust_encoded_len = call.encoded_size() as u32; + let rust_encoded_fees = TransactionPayment::compute_fee(rust_encoded_len, &info, 0); //6387338169067 + assert_eq!(rust_encoded_fees / 4, 5997338169067); + }); +} + +use frame_support::dispatch::DispatchClass; + +#[test] +fn fee_growth_simulator() { + TestNet::reset(); + + Hydra::execute_with(|| { + init_omnipool(); + init_oracle(); + let block_weight = hydradx_runtime::BlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + + for b in 2..=HOURS { + hydradx_run_to_block(b); + hydradx_runtime::System::set_block_consumed_resources(block_weight, 0); + let call = + hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { + asset_in: DOT, + asset_out: 2, + amount: UNITS, + min_buy_amount: 0, + }); + + let info = call.get_dispatch_info(); + let info_len = call.encoded_size() as u32; + let fee = TransactionPayment::compute_fee(info_len, &info, 0); + let next = TransactionPayment::next_fee_multiplier(); + + //let next = SlowAdjustingFeeUpdate::::convert(multiplier); + println!("Swap tx fee: {fee:?} with multiplier: {next:?}"); + } + }); +} + +#[test] +fn price_of_omnipool_swap_with_min_multiplier() { + TestNet::reset(); + + Hydra::execute_with(|| { + //TODO: + //THIS MIGHT help to figure out the exact fee: + //https://substrate.stackexchange.com/questions/4598/testing-transaction-fee-movements + let weight = ::WeightInfo::sell() + .saturating_add(::OmnipoolHooks::on_trade_weight()) + .saturating_add(::OmnipoolHooks::on_liquidity_changed_weight()); + + let fee: primitives::Balance = WeightToFee::weight_to_fee(&weight); + + let sell_old_weight = Weight::from_ref_time(255_333_000 as u64) + .saturating_add(::DbWeight::get().reads(22 as u64)) + .saturating_add(::DbWeight::get().writes(14 as u64)) + .saturating_add(::OmnipoolHooks::on_trade_weight()) + .saturating_add(::OmnipoolHooks::on_liquidity_changed_weight()); + + let fee_old: Balance = WeightToFee::weight_to_fee(&sell_old_weight); + + assert_eq!(fee, fee_old); + }); +} +use sp_runtime::traits::SignedExtension; + +use frame_support::dispatch::Dispatchable; +use frame_system::Origin; +use primitives::constants::time::HOURS; + +#[test] +fn fee_with_tx_payment_pallet() { + TestNet::reset(); + + Hydra::execute_with(|| { + init_omnipool(); + init_oracle(); + hydradx_run_to_block(10); + let alice_balance = hydradx_runtime::Balances::free_balance(&AccountId::from(ALICE)); + + let call = pallet_omnipool::Call::::sell { + asset_in: 2, + asset_out: DOT, + amount: 10 * UNITS, + min_buy_amount: 0, + }; + + let info = call.get_dispatch_info(); + + /*let weight = ::WeightInfo::sell() + .saturating_add(::OmnipoolHooks::on_trade_weight()) + .saturating_add(::OmnipoolHooks::on_liquidity_changed_weight()); + let info = DispatchInfo { + weight: weight, + class: Default::default(), + pays_fee: Default::default(), + };*/ + let len = call.encode().len(); + + let pre_d = pallet_transaction_payment::ChargeTransactionPayment::::from(0) + .pre_dispatch( + &AccountId::from(ALICE), + &hydradx_runtime::RuntimeCall::Omnipool(call.clone()), + &info, + len, + ) + .expect("pre_dispatch error"); + + let post_result = hydradx_runtime::RuntimeCall::Omnipool(call) + .dispatch(hydradx_runtime::RuntimeOrigin::signed(ALICE.into())) + .expect("dispatch failure"); + let actual_fee = TransactionPayment::compute_actual_fee(len.try_into().unwrap(), &info, &post_result, 0); + + assert_ok!(pallet_transaction_payment::ChargeTransactionPayment::< + hydradx_runtime::Runtime, + >::post_dispatch(Some(pre_d), &info, &post_result, len, &Ok(()))); + + let alice_balance_after = hydradx_runtime::Balances::free_balance(&AccountId::from(ALICE)); + let fee = alice_balance - alice_balance_after; + assert_eq!(6_374_151_498_891, fee) + }); +} + +/* +#[ignore] +#[test] +fn price_of_dca_schedule() { + TestNet::reset(); + + Hydra::execute_with(|| { + let schedule1 = Schedule { + owner: AccountId::from(ALICE), + period: 1u32, + total_amount: 1000 * UNITS, + max_retries: None, + stability_threshold: None, + slippage: Some(Permill::from_percent(5)), + order: Order::Sell { + asset_in: HDX, + asset_out: DAI, + amount_in: 500 * UNITS, + min_amount_out: Balance::MIN, + route: create_bounded_vec(vec![Trade { + pool: PoolType::Omnipool, + asset_in: HDX, + asset_out: DAI, + }]), + }, + }; + + let weight = ::WeightInfo::schedule() + + ::AmmTradeWeights::calculate_buy_trade_amounts_weight( + &schedule1 + .order + .get_route_or_default::<::RouteProvider>(), + ); + dbg!(weight); + + let fee: Balance = WeightToFee::weight_to_fee(&weight); + + assert_eq!(fee, UNITS); + }); +}*/ + +fn set_balance(who: hydradx_runtime::AccountId, currency: AssetId, amount: i128) { + assert_ok!(hydradx_runtime::Currencies::update_balance( + hydradx_runtime::RuntimeOrigin::root(), + who, + currency, + amount, + )); +} + +fn init_omnipool() { + let native_price = FixedU128::from_inner(1201500000000000); + let stable_price = FixedU128::from_inner(45_000_000_000); + + assert_ok!(hydradx_runtime::Omnipool::add_token( + hydradx_runtime::RuntimeOrigin::root(), + HDX, + native_price, + Permill::from_percent(10), + hydradx_runtime::Omnipool::protocol_account(), + )); + assert_ok!(hydradx_runtime::Omnipool::add_token( + hydradx_runtime::RuntimeOrigin::root(), + DAI, + stable_price, + Permill::from_percent(100), + hydradx_runtime::Omnipool::protocol_account(), + )); + + let dot_price = FixedU128::from_inner(25_650_000_000_000_000_000); + assert_ok!(hydradx_runtime::Omnipool::add_token( + hydradx_runtime::RuntimeOrigin::root(), + DOT, + dot_price, + Permill::from_percent(100), + AccountId::from(BOB), + )); + + let eth_price = FixedU128::from_inner(71_145_071_145_071); + assert_ok!(hydradx_runtime::Omnipool::add_token( + hydradx_runtime::RuntimeOrigin::root(), + ETH, + eth_price, + Permill::from_percent(100), + AccountId::from(BOB), + )); + + let btc_price = FixedU128::from_inner(9_647_109_647_109_650_000_000_000); + assert_ok!(hydradx_runtime::Omnipool::add_token( + hydradx_runtime::RuntimeOrigin::root(), + BTC, + btc_price, + Permill::from_percent(100), + AccountId::from(BOB), + )); + set_zero_reward_for_referrals(HDX); + set_zero_reward_for_referrals(DAI); + set_zero_reward_for_referrals(DOT); + set_zero_reward_for_referrals(ETH); +} + +/// This function executes one sell and buy with HDX for all assets in the omnipool. This is necessary to +/// oracle have a prices for the assets. +/// NOTE: It's necessary to change parachain block to oracle have prices. +fn init_oracle() { + let trader = DAVE; + + set_balance(trader.into(), HDX, 1_000 * UNITS as i128); + set_balance(trader.into(), DOT, 1_000 * DOT_UNITS as i128); + set_balance(trader.into(), ETH, 1_000 * ETH_UNITS as i128); + set_balance(trader.into(), BTC, 1_000 * BTC_UNITS as i128); + + assert_ok!(hydradx_runtime::Omnipool::sell( + hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), + DOT, + HDX, + 2 * DOT_UNITS, + 0, + )); + + assert_ok!(hydradx_runtime::Omnipool::buy( + hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), + DOT, + HDX, + 2 * DOT_UNITS, + u128::MAX + )); + + assert_ok!(hydradx_runtime::Omnipool::sell( + hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), + ETH, + HDX, + 2 * ETH_UNITS, + 0, + )); + + assert_ok!(hydradx_runtime::Omnipool::buy( + hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), + ETH, + HDX, + 2 * ETH_UNITS, + u128::MAX + )); + + assert_ok!(hydradx_runtime::Omnipool::sell( + hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), + BTC, + HDX, + 2 * BTC_UNITS, + 0, + )); + + assert_ok!(hydradx_runtime::Omnipool::buy( + hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), + BTC, + HDX, + 2 * BTC_UNITS, + u128::MAX + )); +} diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs index 553a10b8d..ee5157011 100644 --- a/integration-tests/src/lib.rs +++ b/integration-tests/src/lib.rs @@ -10,6 +10,8 @@ mod dust_removal_whitelist; mod dynamic_fees; mod evm; mod exchange_asset; +//mod fee; +mod fee_calculation; mod non_native_fee; mod omnipool_init; mod omnipool_liquidity_mining; diff --git a/integration-tests/src/oracle.rs b/integration-tests/src/oracle.rs index 12d36a8e9..aa4282500 100644 --- a/integration-tests/src/oracle.rs +++ b/integration-tests/src/oracle.rs @@ -23,6 +23,7 @@ pub fn hydradx_run_to_block(to: BlockNumber) { hydradx_runtime::System::on_finalize(b); hydradx_runtime::EmaOracle::on_finalize(b); + hydradx_runtime::TransactionPayment::on_finalize(b); hydradx_runtime::System::on_initialize(b + 1); hydradx_runtime::EmaOracle::on_initialize(b + 1); From 3961f4b9e4ef551da1e79034e1bbad0d505f9586 Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 23 Jan 2024 08:51:58 +0100 Subject: [PATCH 07/64] reduce fee by 2/3 and make the fee growth faster in full chain congestion --- integration-tests/Cargo.toml | 2 +- integration-tests/src/fee_calculation.rs | 274 +++++++++++++++++++---- primitives/src/constants.rs | 2 +- rococo-local/config-zombienet.json | 2 +- runtime/hydradx/src/system.rs | 4 +- runtime/hydradx/src/tests.rs | 46 +++- scripts/init-testnet/ddos/ddos_tx.ts | 4 +- 7 files changed, 280 insertions(+), 54 deletions(-) diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index af0124f56..e428dbfa6 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -125,7 +125,7 @@ hex-literal = "0.4.1" pretty_assertions = "1.2.1" pallet-relaychain-info = { workspace = true } xcm-emulator = { git = "https://github.com/shaunxw/xcm-simulator", rev = "754f3b90ecc65af735a6c9a2e1792c5253926ff6" } - +test-utils = { workspace = true } [features] default = ["std"] std = [ diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs index d760f8f20..71b364bb8 100644 --- a/integration-tests/src/fee_calculation.rs +++ b/integration-tests/src/fee_calculation.rs @@ -5,13 +5,13 @@ use frame_support::assert_ok; use frame_support::dispatch::GetDispatchInfo; use frame_support::pallet_prelude::Weight; use frame_support::weights::WeightToFee as WeightToFeeTrait; -use hydradx_runtime::Runtime; -use hydradx_runtime::TransactionPayment; use hydradx_runtime::WeightToFee; +use hydradx_runtime::{Runtime, UncheckedExtrinsic}; +use hydradx_runtime::{SignedExtra, TransactionPayment}; use pallet_dynamic_fees::types::FeeEntry; use pallet_omnipool::traits::OmnipoolHooks; use pallet_omnipool::WeightInfo; -use primitives::AssetId; +use primitives::{AssetId, Balance}; use sp_core::Encode; use sp_runtime::{FixedU128, Permill}; use xcm_emulator::TestExt; @@ -21,11 +21,224 @@ const ETH_UNITS: u128 = 1_000_000_000_000_000_000; //TODO: clean up in this test file +use frame_support::dispatch::DispatchClass; ///original fee - 1.560005867338 ///1 cent per swap, we don't want to be more expensive ///300 blocks to reach the max ///30k per hour use frame_support::dispatch::DispatchInfo; +use frame_support::weights::ConstantMultiplier; +use hex_literal::hex; +use hydradx_runtime::TransactionByteFee; +use sp_runtime::testing::TestXt; +use sp_runtime::traits::CheckedDiv; +use sp_runtime::FixedPointNumber; +use test_utils::assert_eq_approx; + +const HDX_USD_SPOT_PRICE_IN_CENTS: Balance = 2; //1HDX =~ 2 CENTS; +const SWAP_ENCODED_LEN: u32 = 146; //We use this as this is what the UI send as length when omnipool swap is executed + +#[test] +fn min_swap_fee() { + TestNet::reset(); + Hydra::execute_with(|| { + pallet_transaction_payment::pallet::NextFeeMultiplier::::put( + hydradx_runtime::MinimumMultiplier::get(), + ); + + let call = hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { + asset_in: DOT, + asset_out: 2, + amount: UNITS, + min_buy_amount: 0, + }); + + let info = call.get_dispatch_info(); + let info_len = 146; + let fee = TransactionPayment::compute_fee(info_len, &info, 0); + let fee_in_cent = FixedU128::from(fee * HDX_USD_SPOT_PRICE_IN_CENTS).div(UNITS.into()); + let tolerance = FixedU128::from((2, (UNITS / 10_000))); + println!("Swap tx fee in cents: {fee_in_cent:?}"); + + assert_eq_approx!( + fee_in_cent, + FixedU128::from_float(1.040003910584000000), + tolerance, + "The min fee should be ~1 cent (0.01$)" + ); + }); +} + +#[test] +fn max_swap_fee() { + TestNet::reset(); + Hydra::execute_with(|| { + pallet_transaction_payment::pallet::NextFeeMultiplier::::put( + hydradx_runtime::MaximumMultiplier::get(), + ); + + let call = hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { + asset_in: DOT, + asset_out: 2, + amount: UNITS, + min_buy_amount: 0, + }); + + let info = call.get_dispatch_info(); + let info_len = 146; //We use this as this is what the UI send as length when omnipool swap is executed + let fee = TransactionPayment::compute_fee(info_len, &info, 0); + let fee_in_cent = FixedU128::from(fee * HDX_USD_SPOT_PRICE_IN_CENTS).div(UNITS.into()); + let tolerance = FixedU128::from((2, (UNITS / 10_000))); + assert_eq_approx!( + fee_in_cent, + FixedU128::from_float(501.719523758898000000), + tolerance, + "The max fee should be ~200 cent (2$)" + ); + }); +} + +#[test] +fn fee_growth_simulator_starting_with_genesis_chain() { + TestNet::reset(); + + Hydra::execute_with(|| { + let prod_init_multiplier = FixedU128::from_inner(1000000000000000000); + + pallet_transaction_payment::pallet::NextFeeMultiplier::::put(prod_init_multiplier); + init_omnipool(); + init_oracle(); + let block_weight = hydradx_runtime::BlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + + for b in 2..=HOURS { + hydradx_run_to_block(b); + hydradx_runtime::System::set_block_consumed_resources(block_weight, 0); + let call = + hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { + asset_in: HDX, + asset_out: 2, + amount: 10 * UNITS, + min_buy_amount: 10000, + }); + + let info = call.get_dispatch_info(); + let fee = TransactionPayment::compute_fee(SWAP_ENCODED_LEN, &info, 0); + let fee_in_cent = FixedU128::from(fee * HDX_USD_SPOT_PRICE_IN_CENTS).div(UNITS.into()); + + let next = TransactionPayment::next_fee_multiplier(); + + //let next = SlowAdjustingFeeUpdate::::convert(multiplier); + println!("Swap tx fee in cents: {fee_in_cent:?} at block {b:?} with multiplier: {next:?}"); + } + }); +} + +#[test] +fn fee_growth_simulator_with_idle_chain() { + TestNet::reset(); + + Hydra::execute_with(|| { + //We simulate that the chain has no activity so the MinimumMultiplier kept diverged to absolute minimum + pallet_transaction_payment::pallet::NextFeeMultiplier::::put( + hydradx_runtime::MinimumMultiplier::get(), + ); + + init_omnipool(); + init_oracle(); + let block_weight = hydradx_runtime::BlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + + for b in 2..=HOURS { + hydradx_run_to_block(b); + hydradx_runtime::System::set_block_consumed_resources(block_weight, 0); + let call = + hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { + asset_in: HDX, + asset_out: 2, + amount: 10 * UNITS, + min_buy_amount: 10000, + }); + + let info = call.get_dispatch_info(); + let fee = TransactionPayment::compute_fee(SWAP_ENCODED_LEN, &info, 0); + let fee_in_cent = FixedU128::from(fee * HDX_USD_SPOT_PRICE_IN_CENTS).div(UNITS.into()); + + let next = TransactionPayment::next_fee_multiplier(); + + //let next = SlowAdjustingFeeUpdate::::convert(multiplier); + println!("Swap tx fee in cents: {fee_in_cent:?} at block {b:?} with multiplier: {next:?}"); + } + }); +} + +#[test] +fn fee_asd() { + TestNet::reset(); + Hydra::execute_with(|| { + let call = hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { + asset_in: DOT, + asset_out: 2, + amount: UNITS, + min_buy_amount: 0, + }); + + let encoded = + hex!["3b05000000000500000000a0724e18090000000000000000000000000000000000000000000000000000"].to_vec(); + + let info = call.get_dispatch_info(); + + /*let length = ::CodeLength::get(); + assert_eq!(length, 0);*/ + + let origin = 111111; + let extra = (); + let xt = TestXt::new(call.clone(), Some((origin, extra))); + let info = xt.get_dispatch_info(); + let ext = xt.encode(); + let len = ext.len() as u32; + assert_eq!(len, 51); + + let s = call.encode(); + assert_eq!(s.len() as u32, 66); + + /*let unchecked = UncheckedExtrinsic::new_signed( + call.into(), + sp_runtime::AccountId32::from(ALICE).into(), + Signature::default(), + SignedExtra::default(), + );*/ + + let unadjusted_weight_fee: primitives::Balance = WeightToFee::weight_to_fee(&info.weight); + + //Prod weight + let prod_low_multiplier = FixedU128::from_inner(1000000000000); + assert_eq!(prod_low_multiplier, FixedU128::from_rational(1, 10)); + let prod_adjusted_weight = prod_low_multiplier.saturating_mul_int(unadjusted_weight_fee); + assert_eq!(prod_adjusted_weight, 5867338); + + //Zombienet weight + let prod_init_multiplier = FixedU128::from_inner(999580731830769414); + let prod_adjusted_weight = prod_init_multiplier.saturating_mul_int(unadjusted_weight_fee); + assert_eq!(prod_adjusted_weight, 5864878180934); + + let len = call.encoded_size() as u32; + assert_eq!(len, 146); //The length fee is a per-byte fee multiplier for the size of the transaction in bytes. + + let len_fee = + ConstantMultiplier::::weight_to_fee(&Weight::from_ref_time(len as u64)); + assert_eq!(len_fee, 1460000000000); + + //pallet_transaction_payment INFO: LEN FEE: 1460000000000 + //pallet_transaction_payment INFO: BASE FEE: 100000000000 + + //let base_fee = Self::weight_to_fee(T::BlockWeights::get().get(class).base_extrinsic); + }); +} #[test] fn fee_with_min_multiplier() { @@ -49,26 +262,26 @@ fn fee_with_min_multiplier() { let info = call.get_dispatch_info(); - /*pallet_transaction_payment::pallet::NextFeeMultiplier::::put( + pallet_transaction_payment::pallet::NextFeeMultiplier::::put( hydradx_runtime::MinimumMultiplier::get(), - );*/ + ); let multiplier = pallet_transaction_payment::pallet::NextFeeMultiplier::::get(); //assert_eq!(multiplier, 1.into()); let rust_encoded_len = call.encoded_size() as u32; let rust_encoded_fees = TransactionPayment::compute_fee(rust_encoded_len, &info, 0); //638733816906 - assert_eq!(rust_encoded_fees / 4, 1596834542266); + assert_eq!(rust_encoded_fees, 6377250159654); /*let post = PostDispatchInfo { actual_weight: Some(Weight::from_ref_time(55)), //520000033053 pays_fee: Default::default(), }; let rust_encoded_fees = TransactionPayment::compute_actual_fee(rust_encoded_len, &info, &post, 0);*/ - hydradx_run_to_block(3); + /*hydradx_run_to_block(3); hydradx_run_to_block(4); hydradx_run_to_block(5); - hydradx_run_to_block(6); + hydradx_run_to_block(6);*/ }); } @@ -105,42 +318,6 @@ fn fee_with_max_multiplier() { }); } -use frame_support::dispatch::DispatchClass; - -#[test] -fn fee_growth_simulator() { - TestNet::reset(); - - Hydra::execute_with(|| { - init_omnipool(); - init_oracle(); - let block_weight = hydradx_runtime::BlockWeights::get() - .get(DispatchClass::Normal) - .max_total - .unwrap(); - - for b in 2..=HOURS { - hydradx_run_to_block(b); - hydradx_runtime::System::set_block_consumed_resources(block_weight, 0); - let call = - hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { - asset_in: DOT, - asset_out: 2, - amount: UNITS, - min_buy_amount: 0, - }); - - let info = call.get_dispatch_info(); - let info_len = call.encoded_size() as u32; - let fee = TransactionPayment::compute_fee(info_len, &info, 0); - let next = TransactionPayment::next_fee_multiplier(); - - //let next = SlowAdjustingFeeUpdate::::convert(multiplier); - println!("Swap tx fee: {fee:?} with multiplier: {next:?}"); - } - }); -} - #[test] fn price_of_omnipool_swap_with_min_multiplier() { TestNet::reset(); @@ -170,6 +347,7 @@ use sp_runtime::traits::SignedExtension; use frame_support::dispatch::Dispatchable; use frame_system::Origin; +use primitives::constants::currency::UNITS; use primitives::constants::time::HOURS; #[test] @@ -210,6 +388,14 @@ fn fee_with_tx_payment_pallet() { ) .expect("pre_dispatch error"); + let pre_d_len = pallet_transaction_payment::ChargeTransactionPayment::::from(0) + .pre_dispatch( + &AccountId::from(ALICE), + &hydradx_runtime::RuntimeCall::Omnipool(call.clone()), + &info, + len, + ); + let post_result = hydradx_runtime::RuntimeCall::Omnipool(call) .dispatch(hydradx_runtime::RuntimeOrigin::signed(ALICE.into())) .expect("dispatch failure"); diff --git a/primitives/src/constants.rs b/primitives/src/constants.rs index 5143648e0..9519512e0 100644 --- a/primitives/src/constants.rs +++ b/primitives/src/constants.rs @@ -20,7 +20,7 @@ pub mod currency { pub const FORTUNE: Balance = u128::MAX; pub const UNITS: Balance = 1_000_000_000_000; - pub const DOLLARS: Balance = UNITS * 100; // 100 UNITS ~= 1 $ + pub const DOLLARS: Balance = UNITS * 100 / 3; // 100 UNITS ~= 1 $, and we divide by three as HDX price is high (~0.02$), but we want to reduce the fee price pub const CENTS: Balance = DOLLARS / 100; // 1 UNITS ~= 1 cent pub const MILLICENTS: Balance = CENTS / 1_000; pub const NATIVE_EXISTENTIAL_DEPOSIT: Balance = CENTS; diff --git a/rococo-local/config-zombienet.json b/rococo-local/config-zombienet.json index f75e300c8..4f322e966 100644 --- a/rococo-local/config-zombienet.json +++ b/rococo-local/config-zombienet.json @@ -41,7 +41,7 @@ { "name": "alice", "command": "../target/release/hydradx", - "args": ["--pruning=archive"], + "args": ["--pruning=archive", "--log=info"], "ws_port": 9988, "rpc_port": 9999 }, diff --git a/runtime/hydradx/src/system.rs b/runtime/hydradx/src/system.rs index 4b96177bb..e5b3a9f06 100644 --- a/runtime/hydradx/src/system.rs +++ b/runtime/hydradx/src/system.rs @@ -452,12 +452,12 @@ parameter_types! { pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to /// change the fees more rapidly. - pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(6, 100_000); + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(10, 119); /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure /// that combined with `AdjustmentVariable`, we can recover from the minimum. pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); /// The maximum amount of the multiplier. - pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(4); + pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(128); } impl pallet_transaction_payment::Config for Runtime { diff --git a/runtime/hydradx/src/tests.rs b/runtime/hydradx/src/tests.rs index 1fada20ed..a6f90c3bc 100644 --- a/runtime/hydradx/src/tests.rs +++ b/runtime/hydradx/src/tests.rs @@ -90,7 +90,6 @@ where } #[test] -#[ignore] fn multiplier_can_grow_from_zero() { let minimum_multiplier = MinimumMultiplier::get(); let target = TargetBlockFullness::get() * BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); @@ -103,16 +102,57 @@ fn multiplier_can_grow_from_zero() { } #[test] -#[ignore] fn multiplier_growth_simulator() { // calculate the value of the fee multiplier after one hour of operation with fully loaded blocks + let max_multiplier = MaximumMultiplier::get(); + println!("max multiplier = {max_multiplier:?}"); + let mut multiplier = Multiplier::saturating_from_integer(1); let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); for _block_num in 1..=HOURS { run_with_system_weight(block_weight, || { let next = SlowAdjustingFeeUpdate::::convert(multiplier); // ensure that it is growing as well. - assert!(next > multiplier, "{next:?} !>= {multiplier:?}"); + //assert!(next > multiplier, "{next:?} !>= {multiplier:?}"); + println!("multiplier = {multiplier:?}"); + multiplier = next; + }); + } + println!("multiplier = {multiplier:?}"); +} + +#[test] +fn fee_growth_simulator() { + use frame_support::traits::OnFinalize; + // calculate the value of the fee multiplier after one hour of operation with fully loaded blocks + let max_multiplier = MaximumMultiplier::get(); + println!("--- FEE GROWTH SIMULATOR STARTS ---"); + + println!("With max multiplier = {max_multiplier:?}"); + + let mut multiplier = Multiplier::saturating_from_integer(1); + let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); + for _block_num in 1..=HOURS { + run_with_system_weight(block_weight, || { + let b = crate::System::block_number(); + + let call = pallet_omnipool::Call::::sell { + asset_in: 2, + asset_out: 0, + amount: 1_000_000_000_000, + min_buy_amount: 0, + }; + let call_len = call.encoded_size() as u32; + let info = call.get_dispatch_info(); + + let next = TransactionPayment::next_fee_multiplier(); + let call_fee = TransactionPayment::compute_fee(call_len, &info, 0); + + TransactionPayment::on_finalize(b + 1); + crate::System::set_block_number(b + 1); + + //let next = SlowAdjustingFeeUpdate::::convert(multiplier); + println!("Trade fee = {call_fee:?} with multiplier = {multiplier:?}"); multiplier = next; }); } diff --git a/scripts/init-testnet/ddos/ddos_tx.ts b/scripts/init-testnet/ddos/ddos_tx.ts index 3153dd8b1..3c0ec376f 100644 --- a/scripts/init-testnet/ddos/ddos_tx.ts +++ b/scripts/init-testnet/ddos/ddos_tx.ts @@ -67,13 +67,13 @@ async function doOmnipoolSells(api, user, block) { //If there is a new block if (!(Math.abs(blockNumber - prev_block) < Number.EPSILON)) { - let sells_per_block = 1; + let sells_per_block = 62; for (let i = 0; i < sells_per_block; i++) { let user_pub_key = user.publicKey; const nonce = await api.rpc.system.accountNextIndex(user_pub_key); const tip = 1; - await omniSell(api, user, nonce, tip) + await omniSell(api, user, nonce, tip) } //Print out block feeresult From 0b413b7102293e283082a08eccfad4bb6440d16b Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 23 Jan 2024 08:59:07 +0100 Subject: [PATCH 08/64] change port for zombienet --- scripts/init-testnet/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/init-testnet/index.js b/scripts/init-testnet/index.js index 0b12c8e9c..f1ba3d055 100644 --- a/scripts/init-testnet/index.js +++ b/scripts/init-testnet/index.js @@ -3,7 +3,7 @@ const { ApiPromise, WsProvider } = require('@polkadot/api'); const { Keyring } = require('@polkadot/keyring'); async function main () { - let rpcAddr = process.argv[2] || 'ws://localhost:9946'; + let rpcAddr = process.argv[2] || 'ws://localhost:9988'; console.log(`\nConnecting to RPC node: ${rpcAddr}\n`); From 50230b1b437a9373f7153f76bb37ae831418d9aa Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 23 Jan 2024 14:31:44 +0100 Subject: [PATCH 09/64] adjust fee tests --- Cargo.lock | 1 + integration-tests/src/fee_calculation.rs | 313 +---------------------- 2 files changed, 10 insertions(+), 304 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9c4a617c..51027b9fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10885,6 +10885,7 @@ dependencies = [ "sp-transaction-pool", "sp-trie", "sp-version", + "test-utils", "tokio", "xcm", "xcm-builder", diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs index 71b364bb8..dd2da4152 100644 --- a/integration-tests/src/fee_calculation.rs +++ b/integration-tests/src/fee_calculation.rs @@ -2,39 +2,20 @@ use crate::{oracle::hydradx_run_to_block, polkadot_test_net::*}; use frame_support::assert_ok; +use frame_support::dispatch::DispatchClass; use frame_support::dispatch::GetDispatchInfo; -use frame_support::pallet_prelude::Weight; -use frame_support::weights::WeightToFee as WeightToFeeTrait; -use hydradx_runtime::WeightToFee; -use hydradx_runtime::{Runtime, UncheckedExtrinsic}; -use hydradx_runtime::{SignedExtra, TransactionPayment}; -use pallet_dynamic_fees::types::FeeEntry; -use pallet_omnipool::traits::OmnipoolHooks; -use pallet_omnipool::WeightInfo; +use hydradx_runtime::TransactionPayment; +use primitives::constants::currency::UNITS; +use primitives::constants::time::HOURS; use primitives::{AssetId, Balance}; -use sp_core::Encode; use sp_runtime::{FixedU128, Permill}; use xcm_emulator::TestExt; -const DOT_UNITS: u128 = 10_000_000_000; -const BTC_UNITS: u128 = 10_000_000; -const ETH_UNITS: u128 = 1_000_000_000_000_000_000; -//TODO: clean up in this test file - -use frame_support::dispatch::DispatchClass; -///original fee - 1.560005867338 -///1 cent per swap, we don't want to be more expensive -///300 blocks to reach the max -///30k per hour -use frame_support::dispatch::DispatchInfo; -use frame_support::weights::ConstantMultiplier; -use hex_literal::hex; -use hydradx_runtime::TransactionByteFee; -use sp_runtime::testing::TestXt; -use sp_runtime::traits::CheckedDiv; -use sp_runtime::FixedPointNumber; use test_utils::assert_eq_approx; +const DOT_UNITS: u128 = 10_000_000_000; +const BTC_UNITS: u128 = 10_000_000; +const ETH_UNITS: u128 = 1_000_000_000_000_000_000; const HDX_USD_SPOT_PRICE_IN_CENTS: Balance = 2; //1HDX =~ 2 CENTS; const SWAP_ENCODED_LEN: u32 = 146; //We use this as this is what the UI send as length when omnipool swap is executed @@ -91,9 +72,9 @@ fn max_swap_fee() { let tolerance = FixedU128::from((2, (UNITS / 10_000))); assert_eq_approx!( fee_in_cent, - FixedU128::from_float(501.719523758898000000), + FixedU128::from_float(1000.1), tolerance, - "The max fee should be ~200 cent (2$)" + "The max fee should be ~1000 cent (10$)" ); }); } @@ -176,282 +157,6 @@ fn fee_growth_simulator_with_idle_chain() { }); } -#[test] -fn fee_asd() { - TestNet::reset(); - Hydra::execute_with(|| { - let call = hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { - asset_in: DOT, - asset_out: 2, - amount: UNITS, - min_buy_amount: 0, - }); - - let encoded = - hex!["3b05000000000500000000a0724e18090000000000000000000000000000000000000000000000000000"].to_vec(); - - let info = call.get_dispatch_info(); - - /*let length = ::CodeLength::get(); - assert_eq!(length, 0);*/ - - let origin = 111111; - let extra = (); - let xt = TestXt::new(call.clone(), Some((origin, extra))); - let info = xt.get_dispatch_info(); - let ext = xt.encode(); - let len = ext.len() as u32; - assert_eq!(len, 51); - - let s = call.encode(); - assert_eq!(s.len() as u32, 66); - - /*let unchecked = UncheckedExtrinsic::new_signed( - call.into(), - sp_runtime::AccountId32::from(ALICE).into(), - Signature::default(), - SignedExtra::default(), - );*/ - - let unadjusted_weight_fee: primitives::Balance = WeightToFee::weight_to_fee(&info.weight); - - //Prod weight - let prod_low_multiplier = FixedU128::from_inner(1000000000000); - assert_eq!(prod_low_multiplier, FixedU128::from_rational(1, 10)); - let prod_adjusted_weight = prod_low_multiplier.saturating_mul_int(unadjusted_weight_fee); - assert_eq!(prod_adjusted_weight, 5867338); - - //Zombienet weight - let prod_init_multiplier = FixedU128::from_inner(999580731830769414); - let prod_adjusted_weight = prod_init_multiplier.saturating_mul_int(unadjusted_weight_fee); - assert_eq!(prod_adjusted_weight, 5864878180934); - - let len = call.encoded_size() as u32; - assert_eq!(len, 146); //The length fee is a per-byte fee multiplier for the size of the transaction in bytes. - - let len_fee = - ConstantMultiplier::::weight_to_fee(&Weight::from_ref_time(len as u64)); - assert_eq!(len_fee, 1460000000000); - - //pallet_transaction_payment INFO: LEN FEE: 1460000000000 - //pallet_transaction_payment INFO: BASE FEE: 100000000000 - - //let base_fee = Self::weight_to_fee(T::BlockWeights::get().get(class).base_extrinsic); - }); -} - -#[test] -fn fee_with_min_multiplier() { - TestNet::reset(); - Hydra::execute_with(|| { - init_omnipool(); - init_oracle(); - hydradx_run_to_block(2); - - assert_ok!(hydradx_runtime::MultiTransactionPayment::set_currency( - hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), - HDX, - )); - - let call = pallet_omnipool::Call::::sell { - asset_in: HDX, - asset_out: DOT, - amount: UNITS, - min_buy_amount: 0, - }; - - let info = call.get_dispatch_info(); - - pallet_transaction_payment::pallet::NextFeeMultiplier::::put( - hydradx_runtime::MinimumMultiplier::get(), - ); - - let multiplier = pallet_transaction_payment::pallet::NextFeeMultiplier::::get(); - //assert_eq!(multiplier, 1.into()); - - let rust_encoded_len = call.encoded_size() as u32; - let rust_encoded_fees = TransactionPayment::compute_fee(rust_encoded_len, &info, 0); //638733816906 - assert_eq!(rust_encoded_fees, 6377250159654); - - /*let post = PostDispatchInfo { - actual_weight: Some(Weight::from_ref_time(55)), //520000033053 - pays_fee: Default::default(), - }; - let rust_encoded_fees = TransactionPayment::compute_actual_fee(rust_encoded_len, &info, &post, 0);*/ - /*hydradx_run_to_block(3); - hydradx_run_to_block(4); - hydradx_run_to_block(5); - hydradx_run_to_block(6);*/ - }); -} - -#[test] -fn fee_with_max_multiplier() { - TestNet::reset(); - - Hydra::execute_with(|| { - init_omnipool(); - init_oracle(); - hydradx_run_to_block(10); - - assert_ok!(hydradx_runtime::MultiTransactionPayment::set_currency( - hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), - HDX, - )); - - let call = hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { - asset_in: DOT, - asset_out: 2, - amount: UNITS, - min_buy_amount: 0, - }); - - let info = call.get_dispatch_info(); - - pallet_transaction_payment::pallet::NextFeeMultiplier::::put( - hydradx_runtime::MaximumMultiplier::get(), - ); - - let rust_encoded_len = call.encoded_size() as u32; - let rust_encoded_fees = TransactionPayment::compute_fee(rust_encoded_len, &info, 0); //6387338169067 - assert_eq!(rust_encoded_fees / 4, 5997338169067); - }); -} - -#[test] -fn price_of_omnipool_swap_with_min_multiplier() { - TestNet::reset(); - - Hydra::execute_with(|| { - //TODO: - //THIS MIGHT help to figure out the exact fee: - //https://substrate.stackexchange.com/questions/4598/testing-transaction-fee-movements - let weight = ::WeightInfo::sell() - .saturating_add(::OmnipoolHooks::on_trade_weight()) - .saturating_add(::OmnipoolHooks::on_liquidity_changed_weight()); - - let fee: primitives::Balance = WeightToFee::weight_to_fee(&weight); - - let sell_old_weight = Weight::from_ref_time(255_333_000 as u64) - .saturating_add(::DbWeight::get().reads(22 as u64)) - .saturating_add(::DbWeight::get().writes(14 as u64)) - .saturating_add(::OmnipoolHooks::on_trade_weight()) - .saturating_add(::OmnipoolHooks::on_liquidity_changed_weight()); - - let fee_old: Balance = WeightToFee::weight_to_fee(&sell_old_weight); - - assert_eq!(fee, fee_old); - }); -} -use sp_runtime::traits::SignedExtension; - -use frame_support::dispatch::Dispatchable; -use frame_system::Origin; -use primitives::constants::currency::UNITS; -use primitives::constants::time::HOURS; - -#[test] -fn fee_with_tx_payment_pallet() { - TestNet::reset(); - - Hydra::execute_with(|| { - init_omnipool(); - init_oracle(); - hydradx_run_to_block(10); - let alice_balance = hydradx_runtime::Balances::free_balance(&AccountId::from(ALICE)); - - let call = pallet_omnipool::Call::::sell { - asset_in: 2, - asset_out: DOT, - amount: 10 * UNITS, - min_buy_amount: 0, - }; - - let info = call.get_dispatch_info(); - - /*let weight = ::WeightInfo::sell() - .saturating_add(::OmnipoolHooks::on_trade_weight()) - .saturating_add(::OmnipoolHooks::on_liquidity_changed_weight()); - let info = DispatchInfo { - weight: weight, - class: Default::default(), - pays_fee: Default::default(), - };*/ - let len = call.encode().len(); - - let pre_d = pallet_transaction_payment::ChargeTransactionPayment::::from(0) - .pre_dispatch( - &AccountId::from(ALICE), - &hydradx_runtime::RuntimeCall::Omnipool(call.clone()), - &info, - len, - ) - .expect("pre_dispatch error"); - - let pre_d_len = pallet_transaction_payment::ChargeTransactionPayment::::from(0) - .pre_dispatch( - &AccountId::from(ALICE), - &hydradx_runtime::RuntimeCall::Omnipool(call.clone()), - &info, - len, - ); - - let post_result = hydradx_runtime::RuntimeCall::Omnipool(call) - .dispatch(hydradx_runtime::RuntimeOrigin::signed(ALICE.into())) - .expect("dispatch failure"); - let actual_fee = TransactionPayment::compute_actual_fee(len.try_into().unwrap(), &info, &post_result, 0); - - assert_ok!(pallet_transaction_payment::ChargeTransactionPayment::< - hydradx_runtime::Runtime, - >::post_dispatch(Some(pre_d), &info, &post_result, len, &Ok(()))); - - let alice_balance_after = hydradx_runtime::Balances::free_balance(&AccountId::from(ALICE)); - let fee = alice_balance - alice_balance_after; - assert_eq!(6_374_151_498_891, fee) - }); -} - -/* -#[ignore] -#[test] -fn price_of_dca_schedule() { - TestNet::reset(); - - Hydra::execute_with(|| { - let schedule1 = Schedule { - owner: AccountId::from(ALICE), - period: 1u32, - total_amount: 1000 * UNITS, - max_retries: None, - stability_threshold: None, - slippage: Some(Permill::from_percent(5)), - order: Order::Sell { - asset_in: HDX, - asset_out: DAI, - amount_in: 500 * UNITS, - min_amount_out: Balance::MIN, - route: create_bounded_vec(vec![Trade { - pool: PoolType::Omnipool, - asset_in: HDX, - asset_out: DAI, - }]), - }, - }; - - let weight = ::WeightInfo::schedule() - + ::AmmTradeWeights::calculate_buy_trade_amounts_weight( - &schedule1 - .order - .get_route_or_default::<::RouteProvider>(), - ); - dbg!(weight); - - let fee: Balance = WeightToFee::weight_to_fee(&weight); - - assert_eq!(fee, UNITS); - }); -}*/ - fn set_balance(who: hydradx_runtime::AccountId, currency: AssetId, amount: i128) { assert_ok!(hydradx_runtime::Currencies::update_balance( hydradx_runtime::RuntimeOrigin::root(), From 4828449c3a5207e6d9c1560f7b92d97f07d656d0 Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 23 Jan 2024 14:39:17 +0100 Subject: [PATCH 10/64] make transaction script run for ~1h --- scripts/init-testnet/ddos/ddos_tx.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/init-testnet/ddos/ddos_tx.ts b/scripts/init-testnet/ddos/ddos_tx.ts index 3c0ec376f..79c22759a 100644 --- a/scripts/init-testnet/ddos/ddos_tx.ts +++ b/scripts/init-testnet/ddos/ddos_tx.ts @@ -58,7 +58,7 @@ async function doOmnipoolSells(api, user, block) { const blockNumber = blockInfo.block.header.number; //Change this `ddos_run_duration` variable to define how long (in blocks) the DDOS should take - let ddos_run_duration = 1000; + let ddos_run_duration = 350; let block_spent = blockNumber - block; if (block_spent == ddos_run_duration) { console.log(`The specified blocktime ${block_spent} passed`); From aad910e13e6987b2c5cb20d82144b97d2f8a0ae0 Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 23 Jan 2024 14:39:51 +0100 Subject: [PATCH 11/64] change multiplers to have 500HDX as max fee and reaching in 1h --- runtime/hydradx/src/system.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/hydradx/src/system.rs b/runtime/hydradx/src/system.rs index e5b3a9f06..abf33a235 100644 --- a/runtime/hydradx/src/system.rs +++ b/runtime/hydradx/src/system.rs @@ -452,12 +452,12 @@ parameter_types! { pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to /// change the fees more rapidly. - pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(10, 119); + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(10, 115); /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure /// that combined with `AdjustmentVariable`, we can recover from the minimum. pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); /// The maximum amount of the multiplier. - pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(128); + pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(256); } impl pallet_transaction_payment::Config for Runtime { From fda2c583273b3e50a2132645e9aacebd9caf588d Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 23 Jan 2024 15:44:56 +0100 Subject: [PATCH 12/64] fix tests as fee has been decreased --- integration-tests/src/cross_chain_transfer.rs | 7 ++++--- integration-tests/src/dca.rs | 2 +- integration-tests/src/fee_calculation.rs | 2 +- integration-tests/src/non_native_fee.rs | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/integration-tests/src/cross_chain_transfer.rs b/integration-tests/src/cross_chain_transfer.rs index 3bc596437..0e2e9d0f3 100644 --- a/integration-tests/src/cross_chain_transfer.rs +++ b/integration-tests/src/cross_chain_transfer.rs @@ -51,7 +51,7 @@ fn hydra_should_receive_asset_when_transferred_from_polkadot_relay_chain() { ); }); - let fees = 400641025641; + let fees = 133547008547; Hydra::execute_with(|| { assert_eq!( hydradx_runtime::Tokens::free_balance(1, &AccountId::from(BOB)), @@ -141,7 +141,7 @@ fn hydra_should_receive_asset_when_transferred_from_acala() { ); }); - let fee = 400641025641; + let fee = 133547008547; Hydra::execute_with(|| { assert_eq!( hydradx_runtime::Tokens::free_balance(ACA, &AccountId::from(BOB)), @@ -330,10 +330,11 @@ fn claim_trapped_asset_should_work() { claim_asset(asset.clone(), BOB); + let fee = 100160256410; Hydra::execute_with(|| { assert_eq!( hydradx_runtime::Tokens::free_balance(1, &AccountId::from(BOB)), - 1000 * UNITS + 29_699_519_230_769 + 1000 * UNITS + 30 * UNITS - fee ); let origin = MultiLocation::new(1, X1(Parachain(ACALA_PARA_ID))); diff --git a/integration-tests/src/dca.rs b/integration-tests/src/dca.rs index 5bb221648..80e5a9609 100644 --- a/integration-tests/src/dca.rs +++ b/integration-tests/src/dca.rs @@ -444,7 +444,7 @@ mod omnipool { run_to_block(11, 40); //Assert - assert_balance!(ALICE.into(), DAI, ALICE_INITIAL_DAI_BALANCE + 600 * UNITS); + assert_balance!(ALICE.into(), DAI, ALICE_INITIAL_DAI_BALANCE + 700 * UNITS); //Because the last trade is not enough for a whole trade, it is returned to the user let amount_in = 140_421_094_431_120; diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs index dd2da4152..7c75d6b9f 100644 --- a/integration-tests/src/fee_calculation.rs +++ b/integration-tests/src/fee_calculation.rs @@ -72,7 +72,7 @@ fn max_swap_fee() { let tolerance = FixedU128::from((2, (UNITS / 10_000))); assert_eq_approx!( fee_in_cent, - FixedU128::from_float(1000.1), + FixedU128::from_float(1002.399047518770000000), tolerance, "The max fee should be ~1000 cent (10$)" ); diff --git a/integration-tests/src/non_native_fee.rs b/integration-tests/src/non_native_fee.rs index 46c46e415..5b41518a3 100644 --- a/integration-tests/src/non_native_fee.rs +++ b/integration-tests/src/non_native_fee.rs @@ -64,7 +64,7 @@ fn non_native_fee_payment_works_with_oracle_price_based_on_onchain_route() { ) ); let bob_balance = hydradx_runtime::Tokens::free_balance(BTC, &AccountId::from(BOB)); - assert_eq!(bob_balance, 999_959); + assert_eq!(bob_balance, 999_987); assert_ok!(hydradx_runtime::Balances::set_balance( hydradx_runtime::RuntimeOrigin::root(), @@ -91,7 +91,7 @@ fn non_native_fee_payment_works_with_oracle_price_based_on_onchain_route() { ); let dave_balance = hydradx_runtime::Tokens::free_balance(DAI, &AccountId::from(DAVE)); - assert_eq!(dave_balance, 999_999_999_692_871_594_551); //Price based on oracle with onchain route + assert_eq!(dave_balance, 999_999_999_897_623_864_884); //Price based on oracle with onchain route }); } From 639d7b03ec74b898520f3bebff7cf0f8acf86eb0 Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 24 Jan 2024 08:32:49 +0100 Subject: [PATCH 13/64] adjust constants as weight changed due to polkadot v1. --- primitives/src/constants.rs | 2 +- runtime/hydradx/src/system.rs | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/primitives/src/constants.rs b/primitives/src/constants.rs index fb643b5ca..34be3975f 100644 --- a/primitives/src/constants.rs +++ b/primitives/src/constants.rs @@ -20,7 +20,7 @@ pub mod currency { pub const FORTUNE: Balance = u128::MAX; pub const UNITS: Balance = 1_000_000_000_000; - pub const DOLLARS: Balance = UNITS * 100 / 3; // 100 UNITS ~= 1 $, and we divide by three as HDX price is high (~0.02$), but we want to reduce the fee price + pub const DOLLARS: Balance = UNITS * 100; // 100 UNITS ~= 1 $, and we divide by three as HDX price is high (~0.02$), but we want to reduce the fee price pub const CENTS: Balance = DOLLARS / 100; // 1 UNITS ~= 1 cent pub const MILLICENTS: Balance = CENTS / 1_000; pub const NATIVE_EXISTENTIAL_DEPOSIT: Balance = CENTS; diff --git a/runtime/hydradx/src/system.rs b/runtime/hydradx/src/system.rs index 931efde93..a947e7183 100644 --- a/runtime/hydradx/src/system.rs +++ b/runtime/hydradx/src/system.rs @@ -420,6 +420,9 @@ pub type SlowAdjustingFeeUpdate = pub struct WeightToFee; +const DIVIDER_FOR_FEE: u128 = 3; // We use this to divide fee related constant as HDX price is high (~0.02$), but we want to reduce the fee price + //TODO: make constant for fee related stuff + impl WeightToFeePolynomial for WeightToFee { type Balance = Balance; @@ -435,7 +438,7 @@ impl WeightToFeePolynomial for WeightToFee { /// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. fn polynomial() -> WeightToFeeCoefficients { // extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT - let p = CENTS; // 1_000_000_000_000 + let p = CENTS / DIVIDER_FOR_FEE; // 1_000_000_000_000 let q = 10 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); // 7_919_840_000 smallvec::smallvec![WeightToFeeCoefficient { degree: 1, @@ -447,18 +450,18 @@ impl WeightToFeePolynomial for WeightToFee { } parameter_types! { - pub const TransactionByteFee: Balance = 10 * MILLICENTS; + pub const TransactionByteFee: Balance = 10 * MILLICENTS / DIVIDER_FOR_FEE; /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less /// than this will decrease the weight and more will increase. pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to /// change the fees more rapidly. - pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(10, 115); + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(10, 113); /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure /// that combined with `AdjustmentVariable`, we can recover from the minimum. pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); /// The maximum amount of the multiplier. - pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(256); + pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(320); } impl pallet_transaction_payment::Config for Runtime { From df86c31228cbfee1b5ac53dd9b2030efd4b67d8b Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 24 Jan 2024 09:15:51 +0100 Subject: [PATCH 14/64] reduce evm fees by 2/3 just like we did for normal substrate extrinsics --- integration-tests/src/evm.rs | 4 ++-- runtime/hydradx/src/evm/mod.rs | 8 ++++---- runtime/hydradx/src/system.rs | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index f60a6eb6e..e426a5b09 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -20,8 +20,8 @@ use pretty_assertions::assert_eq; use sp_core::{blake2_256, H160, H256, U256}; use sp_runtime::{traits::SignedExtension, FixedU128, Permill}; use std::borrow::Cow; +use std::ops::Div; use xcm_emulator::TestExt; - const TREASURY_ACCOUNT_INIT_BALANCE: Balance = 1000 * UNITS; mod currency_precompile { @@ -746,7 +746,7 @@ pub fn init_omnipol() { const DISPATCH_ADDR: H160 = addr(1025); fn gas_price() -> U256 { - U256::from(8 * 10_u128.pow(7)) + U256::from(8 * 10_u128.pow(7)).div(3) //We divide by three as we const `FEE_DIVIDER` set to 3 in system.rs } fn create_dispatch_handle(data: Vec) -> MockHandle { diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index f9e84968b..b958b045e 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -19,11 +19,11 @@ // you may not use this file except in compliance with the License. // http://www.apache.org/licenses/LICENSE-2.0 -use crate::TreasuryAccount; pub use crate::{ evm::accounts_conversion::{ExtendedAddressMapping, FindAuthorTruncated}, AssetLocation, Aura, NORMAL_DISPATCH_RATIO, }; +use crate::{TreasuryAccount, FEE_DIVIDER}; use frame_support::{ parameter_types, traits::{Defensive, FindAuthor, Imbalance, OnUnbalanced}, @@ -53,9 +53,9 @@ pub const GAS_PER_SECOND: u64 = 40_000_000; // Approximate ratio of the amount of Weight per Gas. const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; -// Fixed gas price of 0.08 gwei per gas -// pallet-base-fee to be implemented after migration to polkadot-v1.1.0 -const DEFAULT_BASE_FEE_PER_GAS: u128 = 80_000_000; +// Fixed gas price of 0.08 gwei per gas, but also divided with the fee divider as HDX price is high atm (~0.02ï¿ ) +// TODO: pallet-base-fee to be implemented after migration to polkadot-v1.1.0 +const DEFAULT_BASE_FEE_PER_GAS: u128 = 80_000_000 / FEE_DIVIDER; parameter_types! { // We allow for a 75% fullness of a 0.5s block diff --git a/runtime/hydradx/src/system.rs b/runtime/hydradx/src/system.rs index a947e7183..b896e638f 100644 --- a/runtime/hydradx/src/system.rs +++ b/runtime/hydradx/src/system.rs @@ -420,7 +420,7 @@ pub type SlowAdjustingFeeUpdate = pub struct WeightToFee; -const DIVIDER_FOR_FEE: u128 = 3; // We use this to divide fee related constant as HDX price is high (~0.02$), but we want to reduce the fee price +pub const FEE_DIVIDER: u128 = 3; // We use this to divide fee related constant as HDX price is high (~0.02$), but we want to reduce the fee price //TODO: make constant for fee related stuff impl WeightToFeePolynomial for WeightToFee { @@ -438,7 +438,7 @@ impl WeightToFeePolynomial for WeightToFee { /// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. fn polynomial() -> WeightToFeeCoefficients { // extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT - let p = CENTS / DIVIDER_FOR_FEE; // 1_000_000_000_000 + let p = CENTS / FEE_DIVIDER; // 1_000_000_000_000 let q = 10 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); // 7_919_840_000 smallvec::smallvec![WeightToFeeCoefficient { degree: 1, @@ -450,7 +450,7 @@ impl WeightToFeePolynomial for WeightToFee { } parameter_types! { - pub const TransactionByteFee: Balance = 10 * MILLICENTS / DIVIDER_FOR_FEE; + pub const TransactionByteFee: Balance = 10 * MILLICENTS / FEE_DIVIDER; /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less /// than this will decrease the weight and more will increase. pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); From 272ee9d9af5b748b8c833f05aea1f43e3c54575b Mon Sep 17 00:00:00 2001 From: dmoka Date: Mon, 5 Feb 2024 18:14:16 +0100 Subject: [PATCH 15/64] add evm tests and base implementation od dynamic evm fee pallet --- Cargo.lock | 26 ++ Cargo.toml | 2 + integration-tests/Cargo.toml | 1 + integration-tests/src/evm.rs | 61 +++- integration-tests/src/fee_calculation.rs | 72 +++- pallets/dynamic-evm-fee/Cargo.toml | 58 ++++ pallets/dynamic-evm-fee/README.md | 5 + pallets/dynamic-evm-fee/src/lib.rs | 152 ++++++++ pallets/dynamic-evm-fee/src/tests/mock.rs | 327 ++++++++++++++++++ pallets/dynamic-evm-fee/src/tests/mod.rs | 2 + .../src/tests/on_initialize.rs | 54 +++ pallets/dynamic-evm-fee/src/types.rs | 5 + runtime/hydradx/Cargo.toml | 3 + 13 files changed, 759 insertions(+), 9 deletions(-) create mode 100644 pallets/dynamic-evm-fee/Cargo.toml create mode 100644 pallets/dynamic-evm-fee/README.md create mode 100644 pallets/dynamic-evm-fee/src/lib.rs create mode 100644 pallets/dynamic-evm-fee/src/tests/mock.rs create mode 100644 pallets/dynamic-evm-fee/src/tests/mod.rs create mode 100644 pallets/dynamic-evm-fee/src/tests/on_initialize.rs create mode 100644 pallets/dynamic-evm-fee/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 5eb27e2ba..1bb60c76d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4668,6 +4668,7 @@ dependencies = [ "pallet-dca", "pallet-democracy 4.1.0", "pallet-duster", + "pallet-dynamic-evm-fee", "pallet-dynamic-fees", "pallet-elections-phragmen", "pallet-ema-oracle", @@ -7462,6 +7463,31 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "pallet-dynamic-evm-fee" +version = "1.0.0" +dependencies = [ + "frame-support", + "frame-system", + "hydra-dx-math", + "hydradx-traits", + "log", + "orml-tokens", + "orml-traits", + "pallet-balances", + "pallet-currencies", + "pallet-transaction-payment", + "parity-scale-codec", + "primitives", + "scale-info", + "sp-api", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "test-utils", +] + [[package]] name = "pallet-dynamic-fees" version = "1.0.2" diff --git a/Cargo.toml b/Cargo.toml index a094fa340..99f8b0b2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ members = [ 'pallets/democracy', 'runtime/hydradx/src/evm/evm-utility/macro', 'pallets/referrals', + 'pallets/dynamic-evm-fee' ] [workspace.dependencies] @@ -60,6 +61,7 @@ pallet-currencies = { path = "pallets/currencies", default-features = false } pallet-dca = { path = "pallets/dca", default-features = false } pallet-duster = { path = "pallets/duster", default-features = false } pallet-dynamic-fees = { path = "pallets/dynamic-fees", default-features = false } +pallet-dynamic-evm-fee = { path = "pallets/dynamic-evm-fee", default-features = false } pallet-ema-oracle = { path = "pallets/ema-oracle", default-features = false } pallet-genesis-history = { path = "pallets/genesis-history", default-features = false } pallet-liquidity-mining = { path = "pallets/liquidity-mining", default-features = false } diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index c27d0ffeb..faac74eac 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -194,6 +194,7 @@ std = [ "polkadot-runtime/std", "hydradx-runtime/std", "pallet-staking/std", + "scraper/std" ] # we don't include integration tests when benchmarking feature is enabled diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index e426a5b09..deb8598d8 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -14,15 +14,19 @@ use hydradx_runtime::{ }, AssetRegistry, Balances, CallFilter, Currencies, RuntimeCall, RuntimeOrigin, Tokens, TransactionPause, EVM, }; +use hydradx_traits::NativePriceOracle; use orml_traits::MultiCurrency; use pallet_evm::*; use pretty_assertions::assert_eq; use sp_core::{blake2_256, H160, H256, U256}; +use sp_runtime::traits::CheckedDiv; +use sp_runtime::FixedPointNumber; use sp_runtime::{traits::SignedExtension, FixedU128, Permill}; use std::borrow::Cow; use std::ops::Div; use xcm_emulator::TestExt; -const TREASURY_ACCOUNT_INIT_BALANCE: Balance = 1000 * UNITS; + +pub const TREASURY_ACCOUNT_INIT_BALANCE: Balance = 1000 * UNITS; mod currency_precompile { use super::*; @@ -677,6 +681,9 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { let new_treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); let fee_weth_evm = new_treasury_eth_balance - treasury_eth_balance; + println!("FEE in WETH: {:?}", fee_weth_evm); + println!("FEE in hdx: {:?}", fee_weth_native); + let fee_difference = fee_weth_evm - fee_weth_native; let relative_fee_difference = FixedU128::from_rational(fee_difference, fee_weth_native); @@ -690,7 +697,50 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { }) } -fn init_omnipool_with_oracle_for_block_10() { +use hydradx_runtime::evm::PolynomialGasPrice; +pub fn get_evm_fee_in_cent(nonce: u128) -> f64 { + let treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); + + let omni_sell = hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { + asset_in: HDX, + asset_out: DAI, + amount: UNITS, + min_buy_amount: 0, + }); + + let gas_limit = 1000000; + + let gas_price = PolynomialGasPrice::min_gas_price(); + //Execute omnipool via EVM + assert_ok!(EVM::call( + evm_signed_origin(evm_address()), + evm_address(), + DISPATCH_ADDR, + omni_sell.encode(), + U256::from(0), + gas_limit, + gas_price.0 * 10, + None, + Some(U256::from(nonce)), + [].into(), + )); + + let new_treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); + let fee_weth_evm = new_treasury_eth_balance - treasury_eth_balance; + + let weth_price = FixedU128::from_u32(2273); + + let fee_in_cents = weth_price.checked_mul_int(fee_weth_evm).unwrap() as f64 / 1000000000000000000.0; + round(fee_in_cents) +} + +fn round(fee_in_cent: f64) -> f64 { + let decimal_places = 20; + let rounder = 10_f64.powi(decimal_places); + (fee_in_cent * rounder).round() / rounder +} + +pub fn init_omnipool_with_oracle_for_block_10() { init_omnipol(); //do_trade_to_populate_oracle(DAI, HDX, UNITS); set_relaychain_block_number(10); @@ -743,10 +793,11 @@ pub fn init_omnipol() { // TODO: test that we charge approximatelly same fee on evm as with extrinsics directly -const DISPATCH_ADDR: H160 = addr(1025); +pub const DISPATCH_ADDR: H160 = addr(1025); -fn gas_price() -> U256 { - U256::from(8 * 10_u128.pow(7)).div(3) //We divide by three as we const `FEE_DIVIDER` set to 3 in system.rs +//TODO: Here we should use the PROD one, as used specifily in test call +pub fn gas_price() -> U256 { + U256::from(8 * 10_u128.pow(7)).div(3) //We divide by three as we const `FEE_DIVIDER` set to 3 in system.rs. } fn create_dispatch_handle(data: Vec) -> MockHandle { diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs index e22ee9345..f20e6e7e6 100644 --- a/integration-tests/src/fee_calculation.rs +++ b/integration-tests/src/fee_calculation.rs @@ -9,9 +9,8 @@ use primitives::constants::currency::UNITS; use primitives::constants::time::HOURS; use primitives::{AssetId, Balance}; use sp_runtime::{FixedU128, Permill}; -use xcm_emulator::TestExt; - use test_utils::assert_eq_approx; +use xcm_emulator::TestExt; const DOT_UNITS: u128 = 10_000_000_000; const BTC_UNITS: u128 = 10_000_000; @@ -43,7 +42,7 @@ fn min_swap_fee() { assert_eq_approx!( fee_in_cent, - FixedU128::from_float(1.040003140744000000), + FixedU128::from_float(1.043141719216000000), tolerance, "The min fee should be ~1 cent (0.01$)" ); @@ -79,6 +78,8 @@ fn max_swap_fee() { }); } +use crate::evm::get_evm_fee_in_cent; + #[test] fn fee_growth_simulator_starting_with_genesis_chain() { TestNet::reset(); @@ -136,7 +137,7 @@ fn fee_growth_simulator_with_idle_chain() { for b in 2..=HOURS { hydradx_run_to_block(b); - hydradx_runtime::System::set_block_consumed_resources(block_weight, 0); + hydradx_runtime::System::set_block_consumed_resources(block_weight / 3, 0); let call = hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { asset_in: HDX, @@ -156,6 +157,69 @@ fn fee_growth_simulator_with_idle_chain() { } }); } +use pallet_evm::FeeCalculator; +#[test] +fn substrate_evm_free_growth_simulator_with_idle_chain() { + TestNet::reset(); + + Hydra::execute_with(|| { + //We simulate that the chain has no activity so the MinimumMultiplier kept diverged to absolute minimum + pallet_transaction_payment::pallet::NextFeeMultiplier::::put( + hydradx_runtime::MinimumMultiplier::get(), + ); + assert_ok!(hydradx_runtime::Currencies::update_balance( + hydradx_runtime::RuntimeOrigin::root(), + evm_account(), + HDX, + 1000000 * UNITS as i128, + )); + + init_omnipool(); + //init_oracle(); + let block_weight = hydradx_runtime::BlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + + let mut nonce = 0; + + for b in 2..3 { + //=HOURS { + hydradx_run_to_block(b); + hydradx_runtime::System::set_block_consumed_resources(block_weight, 0); + let call = + hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { + asset_in: HDX, + asset_out: 2, + amount: 10 * UNITS, + min_buy_amount: 10000, + }); + + let info = call.get_dispatch_info(); + let fee = TransactionPayment::compute_fee(SWAP_ENCODED_LEN, &info, 0); + //let fee_in_cent = FixedU128::from(fee * HDX_USD_SPOT_PRICE_IN_CENTS).div(UNITS.into()); + //let fee_in_cent = (fee * HDX_USD_SPOT_PRICE_IN_CENTS) as f64 / 1000000000000.0; + let hdx_usd_spot_price = 0.02; + + let fee_in_cent = (fee as f64 * hdx_usd_spot_price) as f64 / 1000000000000.0; + let fee_in_cent = round(fee_in_cent); + + let evm_fee_in_cent = get_evm_fee_in_cent(nonce); + let next = TransactionPayment::next_fee_multiplier(); + + let gas_price = hydradx_runtime::evm::PolynomialGasPrice::min_gas_price(); + + println!("{b:?} - fee: ${fee_in_cent:?} - evm_fee: ${evm_fee_in_cent:?} - multiplier: {next:?} - gas {gas_price:?}"); + nonce = nonce + 1; + } + }); +} + +fn round(fee_in_cent: f64) -> f64 { + let decimal_places = 3; + let rounder = 10_f64.powi(decimal_places); + (fee_in_cent * rounder).round() / rounder +} fn set_balance(who: hydradx_runtime::AccountId, currency: AssetId, amount: i128) { assert_ok!(hydradx_runtime::Currencies::update_balance( diff --git a/pallets/dynamic-evm-fee/Cargo.toml b/pallets/dynamic-evm-fee/Cargo.toml new file mode 100644 index 000000000..0b7889fff --- /dev/null +++ b/pallets/dynamic-evm-fee/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "pallet-dynamic-evm-fee" +version = "1.0.0" +description = "Storing and mutating the dynamic fee for EVM transactions." +authors = ["GalacticCoucil"] +edition = "2021" +license = "Apache 2.0" +repository = "https://github.com/galacticcouncil/warehouse" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "3.4.0" } +scale-info = { version = "2.1.2", default-features = false, features = ["derive"] } +log = { workspace = true } + +# ORML dependencies +orml-traits = { workspace = true } + +# HydraDX traits +hydradx-traits = { workspace = true } +primitives = { workspace = true } +hydra-dx-math = { workspace = true } + +# Substrate dependencies +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-api = { workspace = true } +sp-core = { workspace = true } +sp-std = { workspace = true } +sp-runtime = { workspace = true } +sp-io = { workspace = true } + +[dev-dependencies] +pallet-currencies = { workspace = true } +orml-tokens = { workspace = true, features=["std"] } +pallet-balances = { workspace = true, features=["std"] } +test-utils = { workspace = true } +pallet-transaction-payment = { workspace = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "sp-core/std", + "sp-api/std", + "sp-runtime/std", + "sp-io/std", + "frame-support/std", + "frame-system/std", + "pallet-transaction-payment/std", + "orml-traits/std", + "hydradx-traits/std", + "primitives/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/dynamic-evm-fee/README.md b/pallets/dynamic-evm-fee/README.md new file mode 100644 index 000000000..d3d938873 --- /dev/null +++ b/pallets/dynamic-evm-fee/README.md @@ -0,0 +1,5 @@ +# Relaychain info pallet + +Support pallet for a parachain. Includes various little feaures features realted to relay chain + +- Emits `Initialized` event in on_initialize pallet's method with informaton of current parachain block and current relay chain block. diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs new file mode 100644 index 000000000..11f74c185 --- /dev/null +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -0,0 +1,152 @@ +// This file is part of pallet-relaychain-info. + +// Copyright (C) 2020-2022 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(test)] +mod tests; + +mod types; + +// Re-export pallet items so that they can be accessed from the crate namespace. +pub use pallet::*; + +use crate::types::MultiplierProvider; +use codec::HasCompact; +use frame_support::pallet_prelude::*; +use frame_support::sp_runtime::traits::BlockNumberProvider; +use frame_system::pallet_prelude::BlockNumberFor; +use hydra_dx_math::ema::EmaPrice; +use hydradx_traits::NativePriceOracle; +use primitives::BlockNumber; +use sp_core::U256; +use sp_runtime::FixedPointNumber; +use sp_runtime::FixedPointOperand; +use sp_runtime::FixedU128; +use sp_runtime::Permill; +use sp_runtime::Saturating; + +#[frame_support::pallet] +pub mod pallet { + use crate::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Identifier for the class of asset. + type AssetId: Member + + Parameter + + Default + + Copy + + HasCompact + + MaybeSerializeDeserialize + + MaxEncodedLen + + TypeInfo; + + /// Default base fee per gas value. Used in genesis if no other value specified explicitly. + type DefaultBaseFeePerGas: Get; + + /// Multiplier provider + type Multiplier: MultiplierProvider; + + /// Native price oracle + type NativePriceOracle: NativePriceOracle; + + /// Eth Asset + #[pallet::constant] + type WethAssetId: Get; + } + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::type_value] + pub fn DefaultBaseFeePerGas() -> U256 { + U256::from(T::DefaultBaseFeePerGas::get()) + } + + /// Base Evm Fee + #[pallet::storage] + #[pallet::getter(fn base_evm_fee)] + pub type BaseFeePerGas = StorageValue<_, U256, ValueQuery, DefaultBaseFeePerGas>; + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(_: BlockNumberFor) -> Weight { + BaseFeePerGas::::mutate(|old_base_fee_per_gas| { + let min_gas_price = T::DefaultBaseFeePerGas::get().saturating_div(10); + let max_gas_price = 17304992000u128; //TODO: make it constant + let mut multiplier = T::Multiplier::next(); + + let mut new_base_fee_per_gas = T::DefaultBaseFeePerGas::get() + + multiplier + .saturating_mul_int(T::DefaultBaseFeePerGas::get()) + .saturating_mul(3); + + let reference_price = FixedU128::saturating_from_rational(1, 70000); //TODO: + let Some(hdx_eth_price) = T::NativePriceOracle::price(T::WethAssetId::get()) else { + log::warn!(target: "runtime::dynamic-evm-fee", "Can not get HDX-ETH price from oracle"); + return; + }; + + //TODO: refactor to use cmp + let (price_diff, hdx_price_increased) = if hdx_eth_price > reference_price { + (hdx_eth_price.saturating_sub(reference_price), true) + } else { + (reference_price.saturating_sub(hdx_eth_price), false) + }; + + let Some(percentage_change) = price_diff + .saturating_mul(FixedU128::saturating_from_integer(100)) + .const_checked_div(reference_price) else { + log::warn!(target: "runtime::dynamic-evm-fee", "Can not calculate percentage change"); + return; + }; + + let evm_fee_change = + Permill::from_percent(percentage_change.to_float() as u32).mul_floor(new_base_fee_per_gas); + + if hdx_price_increased { + new_base_fee_per_gas = new_base_fee_per_gas.saturating_sub(evm_fee_change); + } else { + new_base_fee_per_gas = new_base_fee_per_gas.saturating_add(evm_fee_change); + } + + new_base_fee_per_gas = new_base_fee_per_gas.clamp(min_gas_price, max_gas_price); + + *old_base_fee_per_gas = U256::from(new_base_fee_per_gas); + }); + + Weight::default() //TODO: benchmark + } + } + + #[pallet::error] + pub enum Error {} + + #[pallet::event] + #[pallet::generate_deposit(pub(crate) fn deposit_event)] + pub enum Event {} +} + +//#[pallet::call] +//impl Pallet {} diff --git a/pallets/dynamic-evm-fee/src/tests/mock.rs b/pallets/dynamic-evm-fee/src/tests/mock.rs new file mode 100644 index 000000000..4f0f4e712 --- /dev/null +++ b/pallets/dynamic-evm-fee/src/tests/mock.rs @@ -0,0 +1,327 @@ +// This file is part of Basilisk-node. + +// Copyright (C) 2020-2022 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +pub use crate as multi_payment; +use crate::Config; +use hydra_dx_math::types::Ratio; + +use crate as dynamic_evm_fee; +use crate::types::MultiplierProvider; +use frame_support::{ + dispatch::DispatchClass, + parameter_types, + traits::{Everything, Get, Nothing}, + weights::{IdentityFee, Weight}, +}; +use frame_system as system; +use hydra_dx_math::ema::EmaPrice; +use hydradx_traits::router::{RouteProvider, Trade}; +use hydradx_traits::{AssetPairAccountIdFor, NativePriceOracle, OraclePeriod, PriceOracle}; +use orml_traits::currency::MutationHooks; +use orml_traits::parameter_type_with_key; +use pallet_currencies::BasicCurrencyAdapter; +use pallet_transaction_payment::Multiplier; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, FixedU128, Perbill, +}; +use sp_std::cell::RefCell; + +pub type AccountId = u64; +pub type Balance = u128; +pub type AssetId = u32; +pub type Amount = i128; + +pub const INITIAL_BALANCE: Balance = 1_000_000_000_000_000u128; + +pub const ALICE: AccountId = 1; +pub const BOB: AccountId = 2; +pub const FEE_RECEIVER: AccountId = 300; + +pub const HDX: AssetId = 0; +pub const WETH: AssetId = 1; +pub const SUPPORTED_CURRENCY: AssetId = 2000; +pub const SUPPORTED_CURRENCY_WITH_PRICE: AssetId = 3000; +pub const UNSUPPORTED_CURRENCY: AssetId = 4000; +pub const SUPPORTED_CURRENCY_NO_BALANCE: AssetId = 5000; // Used for insufficient balance testing +pub const HIGH_ED_CURRENCY: AssetId = 6000; +pub const HIGH_VALUE_CURRENCY: AssetId = 7000; + +pub const HIGH_ED: Balance = 5; + +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +const MAX_BLOCK_WEIGHT: Weight = Weight::from_parts(1024, 0); + +thread_local! { + static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::zero()); + static MULTIPLIER: RefCell = RefCell::new(Multiplier::from_rational(1,1000)); + static ORACLE_PRICE: RefCell = RefCell::new(FixedU128::from_rational(1, 70000)); +} + +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system, + Balances: pallet_balances, + Currencies: pallet_currencies, + Tokens: orml_tokens, + DynamicEvmFee: dynamic_evm_fee, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 63; + + pub const HdxAssetId: u32 = HDX; + pub const WethAssetId: u32 = WETH; + pub const ExistentialDeposit: u128 = 2; + pub const MaxLocks: u32 = 50; + pub const RegistryStringLimit: u32 = 100; + pub const FeeReceiver: AccountId = FEE_RECEIVER; + + + + pub ExchangeFeeRate: (u32, u32) = (2, 1_000); +} + +impl system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +pub struct MultiplierProviderMock; + +impl MultiplierProvider for MultiplierProviderMock { + fn next() -> Multiplier { + MULTIPLIER.with(|v| *v.borrow()) + } +} + +pub struct NativePriceOracleMock; + +impl NativePriceOracle for NativePriceOracleMock { + fn price(_: AssetId) -> Option { + Some(ORACLE_PRICE.with(|v| *v.borrow())) + } +} + +pub struct DefaultBaseDFeePerGas; + +impl Get for DefaultBaseDFeePerGas { + fn get() -> u128 { + 80_000_000 / 3 + } +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type AssetId = AssetId; + type DefaultBaseFeePerGas = DefaultBaseDFeePerGas; + type Multiplier = MultiplierProviderMock; + type NativePriceOracle = NativePriceOracleMock; + + type WethAssetId = HdxAssetId; +} + +pub struct DefaultRouteProvider; + +impl RouteProvider for DefaultRouteProvider {} + +pub struct PriceProviderMock {} + +impl PriceOracle for PriceProviderMock { + type Price = Ratio; + + fn price(route: &[Trade], _period: OraclePeriod) -> Option { + let asset_a = route.first().unwrap().asset_in; + let asset_b = route.first().unwrap().asset_out; + match (asset_a, asset_b) { + (SUPPORTED_CURRENCY_WITH_PRICE, HDX) => Some(Ratio::new(1, 10)), + _ => None, + } + } +} +impl pallet_balances::Config for Test { + type MaxLocks = MaxLocks; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type MaxHolds = (); + type RuntimeHoldReason = (); +} + +parameter_types! { + pub const MaxReserves: u32 = 50; +} +parameter_type_with_key! { + pub ExistentialDeposits: |currency_id: AssetId| -> Balance { + match *currency_id { + HIGH_ED_CURRENCY => HIGH_ED, + HIGH_VALUE_CURRENCY => 1u128, + _ => 2u128 + } + }; +} + +impl orml_tokens::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Amount = Amount; + type CurrencyId = AssetId; + type WeightInfo = (); + type ExistentialDeposits = ExistentialDeposits; + type MaxLocks = (); + type DustRemovalWhitelist = Nothing; + type ReserveIdentifier = (); + type MaxReserves = MaxReserves; + type CurrencyHooks = (); +} + +impl pallet_currencies::Config for Test { + type RuntimeEvent = RuntimeEvent; + type MultiCurrency = Tokens; + type NativeCurrency = BasicCurrencyAdapter; + type GetNativeCurrencyId = HdxAssetId; + type WeightInfo = (); +} + +pub struct ExtBuilder { + base_weight: Weight, + native_balances: Vec<(AccountId, Balance)>, + endowed_accounts: Vec<(AccountId, AssetId, Balance)>, + account_currencies: Vec<(AccountId, AssetId)>, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { + base_weight: Weight::zero(), + native_balances: vec![(ALICE, INITIAL_BALANCE)], + endowed_accounts: vec![ + (ALICE, HDX, INITIAL_BALANCE), + (ALICE, SUPPORTED_CURRENCY, INITIAL_BALANCE), // used for fallback price test + (ALICE, SUPPORTED_CURRENCY_WITH_PRICE, INITIAL_BALANCE), + ], + + account_currencies: vec![], + } + } +} + +impl ExtBuilder { + pub fn base_weight(mut self, base_weight: u64) -> Self { + self.base_weight = Weight::from_parts(base_weight, 0); + self + } + pub fn account_native_balance(mut self, account: AccountId, balance: Balance) -> Self { + self.native_balances.push((account, balance)); + self + } + pub fn account_tokens(mut self, account: AccountId, asset: AssetId, balance: Balance) -> Self { + self.endowed_accounts.push((account, asset, balance)); + self + } + pub fn with_currencies(mut self, account_currencies: Vec<(AccountId, AssetId)>) -> Self { + self.account_currencies = account_currencies; + self + } + fn set_constants(&self) { + EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight); + } + pub fn build(self) -> sp_io::TestExternalities { + use frame_support::traits::OnInitialize; + + self.set_constants(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self.native_balances, + } + .assimilate_storage(&mut t) + .unwrap(); + + orml_tokens::GenesisConfig:: { + balances: self.endowed_accounts, + } + .assimilate_storage(&mut t) + .unwrap(); + + let core_asset: u32 = 0; + let mut buf: Vec = Vec::new(); + + buf.extend_from_slice(&core_asset.to_le_bytes()); + buf.extend_from_slice(b"HDT"); + buf.extend_from_slice(&core_asset.to_le_bytes()); + + let mut ext: sp_io::TestExternalities = t.into(); + ext.execute_with(|| { + System::set_block_number(1); + // Make sure the prices are up-to-date. + }); + ext + } +} + +pub fn expect_events(e: Vec) { + test_utils::expect_events::(e); +} + +pub fn set_multiplier(multiplier: Multiplier) { + MULTIPLIER.with(|v| { + *v.borrow_mut() = multiplier; + }); +} +pub fn set_oracle_price(price: FixedU128) { + ORACLE_PRICE.with(|v| { + *v.borrow_mut() = price; + }); +} diff --git a/pallets/dynamic-evm-fee/src/tests/mod.rs b/pallets/dynamic-evm-fee/src/tests/mod.rs new file mode 100644 index 000000000..744c15954 --- /dev/null +++ b/pallets/dynamic-evm-fee/src/tests/mod.rs @@ -0,0 +1,2 @@ +mod mock; +mod on_initialize; diff --git a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs new file mode 100644 index 000000000..613452a93 --- /dev/null +++ b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs @@ -0,0 +1,54 @@ +use crate::tests::mock::DynamicEvmFee; +use crate::tests::mock::*; +use crate::tests::*; +use frame_support::traits::OnInitialize; +use hydra_dx_math::ema::EmaPrice; +use pallet_transaction_payment::Multiplier; +use sp_core::U256; +use sp_runtime::FixedU128; + +#[test] +fn should_return_default_base_fee_when_min_multiplier() { + ExtBuilder::default().build().execute_with(|| { + DynamicEvmFee::on_initialize(1); + + let new_base_fee = DynamicEvmFee::base_evm_fee(); + assert_eq!(new_base_fee, U256::from(26746664)); + }); +} + +#[test] +fn should_return_increased_fee_with_max_multiplier() { + ExtBuilder::default().build().execute_with(|| { + set_multiplier(Multiplier::from_rational(320, 1)); + + DynamicEvmFee::on_initialize(1); + + let new_base_fee = DynamicEvmFee::base_evm_fee(); + assert_eq!(new_base_fee, U256::from(17304992000u128)); + }); +} + +#[test] +fn should_return_decreased_fee_when_hdx_pumping_against_eth() { + ExtBuilder::default().build().execute_with(|| { + set_oracle_price(FixedU128::from_rational(11, 700000)); + + DynamicEvmFee::on_initialize(1); + + let new_base_fee = DynamicEvmFee::base_evm_fee(); + assert_eq!(new_base_fee, U256::from(24071998)); + }); +} + +#[test] +fn should_return_increased_fee_when_hdx_dumping_against_eth() { + ExtBuilder::default().build().execute_with(|| { + set_oracle_price(FixedU128::from_rational(9, 700000)); + + DynamicEvmFee::on_initialize(1); + + let new_base_fee = DynamicEvmFee::base_evm_fee(); + assert_eq!(new_base_fee, U256::from(29153863)); + }); +} diff --git a/pallets/dynamic-evm-fee/src/types.rs b/pallets/dynamic-evm-fee/src/types.rs new file mode 100644 index 000000000..3e9cb97c0 --- /dev/null +++ b/pallets/dynamic-evm-fee/src/types.rs @@ -0,0 +1,5 @@ +use sp_runtime::FixedU128; + +pub trait MultiplierProvider { + fn next() -> FixedU128; +} diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index 28f8de74a..5ab60e161 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -31,6 +31,7 @@ pallet-omnipool-liquidity-mining = { workspace = true } pallet-dca = { workspace = true } hydra-dx-math = { workspace = true } pallet-dynamic-fees = { workspace = true } +pallet-dynamic-evm-fee = { workspace = true } pallet-stableswap = { workspace = true } pallet-bonds = { workspace = true } pallet-lbp = { workspace = true } @@ -281,6 +282,7 @@ std = [ "fp-rpc/std", "fp-self-contained/std", "pallet-ethereum/std", + "pallet-dynamic-evm-fee/std", "pallet-evm/std", "pallet-evm-chain-id/std", "pallet-evm-precompile-dispatch/std", @@ -348,6 +350,7 @@ try-runtime= [ "pallet-xyk/try-runtime", "fp-self-contained/try-runtime", "pallet-ethereum/try-runtime", + "pallet-dynamic-evm-fee/try-runtime", "pallet-evm/try-runtime", "pallet-evm-chain-id/try-runtime", "pallet-xyk/try-runtime", From af188e85e5d8719b957d2b181853576a3d9cf88a Mon Sep 17 00:00:00 2001 From: dmoka Date: Mon, 5 Feb 2024 18:58:26 +0100 Subject: [PATCH 16/64] fix evm fee calc by not using float as it is only good for std --- pallets/dynamic-evm-fee/src/lib.rs | 6 ++++-- .../src/tests/on_initialize.rs | 20 +++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 11f74c185..bc6f37848 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -122,8 +122,10 @@ pub mod pallet { return; }; - let evm_fee_change = - Permill::from_percent(percentage_change.to_float() as u32).mul_floor(new_base_fee_per_gas); + let percentage_change_permill = + Permill::from_rational(percentage_change.into_inner(), FixedU128::DIV * 100); + + let evm_fee_change = percentage_change_permill.mul_floor(new_base_fee_per_gas); if hdx_price_increased { new_base_fee_per_gas = new_base_fee_per_gas.saturating_sub(evm_fee_change); diff --git a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs index 613452a93..9e2c579aa 100644 --- a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs +++ b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs @@ -18,7 +18,7 @@ fn should_return_default_base_fee_when_min_multiplier() { } #[test] -fn should_return_increased_fee_with_max_multiplier() { +fn should_increase_evm_fee_with_max_multiplier() { ExtBuilder::default().build().execute_with(|| { set_multiplier(Multiplier::from_rational(320, 1)); @@ -30,7 +30,7 @@ fn should_return_increased_fee_with_max_multiplier() { } #[test] -fn should_return_decreased_fee_when_hdx_pumping_against_eth() { +fn should_decrease_evm_fee_when_hdx_pumping_10percent_against_eth() { ExtBuilder::default().build().execute_with(|| { set_oracle_price(FixedU128::from_rational(11, 700000)); @@ -42,13 +42,25 @@ fn should_return_decreased_fee_when_hdx_pumping_against_eth() { } #[test] -fn should_return_increased_fee_when_hdx_dumping_against_eth() { +fn should_decrease_evm_fee_when_hdx_pumping_1percent_against_eth() { + ExtBuilder::default().build().execute_with(|| { + set_oracle_price(FixedU128::from_rational(101, 7000000)); + + DynamicEvmFee::on_initialize(1); + + let new_base_fee = DynamicEvmFee::base_evm_fee(); + assert_eq!(new_base_fee, U256::from(26479225)); + }); +} + +#[test] +fn should_increase_evm_fee_when_hdx_dumping_10percent_against_eth() { ExtBuilder::default().build().execute_with(|| { set_oracle_price(FixedU128::from_rational(9, 700000)); DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(29153863)); + assert_eq!(new_base_fee, U256::from(29421303)); }); } From 1c6f3348bdfba899a0c1347c5bd2777cd53d37f8 Mon Sep 17 00:00:00 2001 From: dmoka Date: Mon, 5 Feb 2024 19:02:23 +0100 Subject: [PATCH 17/64] remove done todo --- pallets/dynamic-evm-fee/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index bc6f37848..4db3d5106 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -108,7 +108,6 @@ pub mod pallet { return; }; - //TODO: refactor to use cmp let (price_diff, hdx_price_increased) = if hdx_eth_price > reference_price { (hdx_eth_price.saturating_sub(reference_price), true) } else { From 19c02a09158aed070a63f22c4227c94b8996a4aa Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 6 Feb 2024 14:03:51 +0100 Subject: [PATCH 18/64] readjust substrate and evm fees (based on current market prices) with the help of using dynamic evm fee calculation --- Cargo.lock | 1 + integration-tests/Cargo.toml | 4 +- integration-tests/src/cross_chain_transfer.rs | 15 +- integration-tests/src/evm.rs | 36 ++--- integration-tests/src/fee_calculation.rs | 26 ++-- integration-tests/src/non_native_fee.rs | 4 +- integration-tests/src/oracle.rs | 1 + integration-tests/src/polkadot_test_net.rs | 3 +- pallets/dynamic-evm-fee/src/lib.rs | 24 ++-- pallets/dynamic-evm-fee/src/tests/mock.rs | 16 +-- .../src/tests/on_initialize.rs | 24 ++-- runtime/hydradx/src/evm/mod.rs | 136 ++++++++++++++++-- runtime/hydradx/src/lib.rs | 1 + runtime/hydradx/src/system.rs | 8 +- 14 files changed, 215 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1bb60c76d..04f9547a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11295,6 +11295,7 @@ dependencies = [ "pallet-dca", "pallet-democracy 4.1.0", "pallet-duster", + "pallet-dynamic-evm-fee", "pallet-dynamic-fees", "pallet-elections-phragmen", "pallet-ema-oracle", diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index faac74eac..ae590e2e6 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -35,6 +35,7 @@ pallet-relaychain-info = { workspace = true } pallet-route-executor = { workspace = true} pallet-dca = { workspace = true} pallet-dynamic-fees = { workspace = true } +pallet-dynamic-evm-fee = { workspace = true } pallet-staking = { workspace = true} pallet-lbp = { workspace = true} pallet-xyk = { workspace = true} @@ -194,7 +195,8 @@ std = [ "polkadot-runtime/std", "hydradx-runtime/std", "pallet-staking/std", - "scraper/std" + "scraper/std", + "pallet-dynamic-evm-fee/std" ] # we don't include integration tests when benchmarking feature is enabled diff --git a/integration-tests/src/cross_chain_transfer.rs b/integration-tests/src/cross_chain_transfer.rs index ebab0589f..57ad2ec22 100644 --- a/integration-tests/src/cross_chain_transfer.rs +++ b/integration-tests/src/cross_chain_transfer.rs @@ -53,16 +53,16 @@ fn hydra_should_receive_asset_when_transferred_from_polkadot_relay_chain() { ); }); - let fees = 133961344114; + let fees = 66980672057; Hydra::execute_with(|| { - assert_eq!( - hydradx_runtime::Tokens::free_balance(1, &AccountId::from(BOB)), - BOB_INITIAL_NATIVE_BALANCE + 300 * UNITS - fees - ); assert_eq!( hydradx_runtime::Tokens::free_balance(1, &hydradx_runtime::Treasury::account_id()), fees ); + assert_eq!( + hydradx_runtime::Tokens::free_balance(1, &AccountId::from(BOB)), + BOB_INITIAL_NATIVE_BALANCE + 300 * UNITS - fees + ); }); } @@ -143,7 +143,7 @@ fn hydra_should_receive_asset_when_transferred_from_acala() { ); }); - let fee = 107169075291; + let fee = 53584537646; Hydra::execute_with(|| { assert_eq!( hydradx_runtime::Tokens::free_balance(ACA, &AccountId::from(BOB)), @@ -333,11 +333,10 @@ fn claim_trapped_asset_should_work() { claim_asset(asset.clone(), BOB); - let fee = 80376806468; Hydra::execute_with(|| { assert_eq!( hydradx_runtime::Tokens::free_balance(1, &AccountId::from(BOB)), - 1000 * UNITS + 30 * UNITS - fee + 1029_959_811_596_766 //1000 * UNITS + 30 * UNITS - fee ); let origin = MultiLocation::new(1, X1(Parachain(ACALA_PARA_ID))); diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index deb8598d8..ace8487ee 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -5,6 +5,7 @@ use fp_evm::{Context, Transfer}; 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::FixedGasPrice; use hydradx_runtime::{ evm::precompiles::{ addr, @@ -14,13 +15,10 @@ use hydradx_runtime::{ }, AssetRegistry, Balances, CallFilter, Currencies, RuntimeCall, RuntimeOrigin, Tokens, TransactionPause, EVM, }; -use hydradx_traits::NativePriceOracle; use orml_traits::MultiCurrency; use pallet_evm::*; use pretty_assertions::assert_eq; use sp_core::{blake2_256, H160, H256, U256}; -use sp_runtime::traits::CheckedDiv; -use sp_runtime::FixedPointNumber; use sp_runtime::{traits::SignedExtension, FixedU128, Permill}; use std::borrow::Cow; use std::ops::Div; @@ -608,12 +606,16 @@ fn dispatch_should_respect_call_filter() { ); }); } - #[test] fn compare_fee_between_evm_and_native_omnipool_calls() { TestNet::reset(); Hydra::execute_with(|| { + //Set up to idle state where the chain is not utilized at all + pallet_transaction_payment::pallet::NextFeeMultiplier::::put( + hydradx_runtime::MinimumMultiplier::get(), + ); + //Set alice with as fee currency and fund it assert_ok!(hydradx_runtime::MultiTransactionPayment::set_currency( hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), @@ -623,7 +625,7 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { hydradx_runtime::RuntimeOrigin::root(), ALICE.into(), WETH, - 100 * UNITS as i128, + 1000000000 * UNITS as i128, )); //Fund evm account with HDX to dispatch omnipool sell @@ -648,6 +650,8 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { }); let gas_limit = 1000000; + let gas_price = FixedGasPrice::min_gas_price(); + //Execute omnipool via EVM assert_ok!(EVM::call( evm_signed_origin(evm_address()), @@ -656,7 +660,7 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { omni_sell.encode(), U256::from(0), gas_limit, - gas_price(), + gas_price.0 * 10, None, Some(U256::zero()), [].into(), @@ -664,7 +668,7 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { //Pre dispatch the native omnipool call - so withdrawring only the fees for the execution let info = omni_sell.get_dispatch_info(); - let len: usize = 1; + let len: usize = 146; //Just like on the UI assert_ok!( pallet_transaction_payment::ChargeTransactionPayment::::from(0).pre_dispatch( &AccountId::from(ALICE), @@ -680,9 +684,11 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { let new_treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); let fee_weth_evm = new_treasury_eth_balance - treasury_eth_balance; - + /* + assert_eq!(fee_weth_native, 4282317006577); + assert_eq!(fee_weth_evm, 4716541412000); println!("FEE in WETH: {:?}", fee_weth_evm); - println!("FEE in hdx: {:?}", fee_weth_native); + println!("FEE in hdx: {:?}", fee_weth_native);*/ let fee_difference = fee_weth_evm - fee_weth_native; @@ -696,8 +702,8 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { assert!(relative_fee_difference < tolerated_fee_difference); }) } - -use hydradx_runtime::evm::PolynomialGasPrice; +use crate::fee_calculation::ETH_USD_SPOT_PRICE; +//TODO: replace this pub fn get_evm_fee_in_cent(nonce: u128) -> f64 { let treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); @@ -710,7 +716,7 @@ pub fn get_evm_fee_in_cent(nonce: u128) -> f64 { let gas_limit = 1000000; - let gas_price = PolynomialGasPrice::min_gas_price(); + let gas_price = FixedGasPrice::min_gas_price(); //Execute omnipool via EVM assert_ok!(EVM::call( evm_signed_origin(evm_address()), @@ -728,9 +734,7 @@ pub fn get_evm_fee_in_cent(nonce: u128) -> f64 { let new_treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); let fee_weth_evm = new_treasury_eth_balance - treasury_eth_balance; - let weth_price = FixedU128::from_u32(2273); - - let fee_in_cents = weth_price.checked_mul_int(fee_weth_evm).unwrap() as f64 / 1000000000000000000.0; + let fee_in_cents = ETH_USD_SPOT_PRICE * fee_weth_evm as f64 / 1000000000000000000.0; round(fee_in_cents) } @@ -797,7 +801,7 @@ pub const DISPATCH_ADDR: H160 = addr(1025); //TODO: Here we should use the PROD one, as used specifily in test call pub fn gas_price() -> U256 { - U256::from(8 * 10_u128.pow(7)).div(3) //We divide by three as we const `FEE_DIVIDER` set to 3 in system.rs. + U256::from(hydradx_runtime::evm::DEFAULT_BASE_FEE_PER_GAS) //We divide by three as we const `FEE_DIVIDER` set to 3 in system.rs. } fn create_dispatch_handle(data: Vec) -> MockHandle { diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs index f20e6e7e6..22afdba0d 100644 --- a/integration-tests/src/fee_calculation.rs +++ b/integration-tests/src/fee_calculation.rs @@ -17,6 +17,8 @@ const BTC_UNITS: u128 = 10_000_000; const ETH_UNITS: u128 = 1_000_000_000_000_000_000; const HDX_USD_SPOT_PRICE_IN_CENTS: Balance = 2; //1HDX =~ 2 CENTS; const SWAP_ENCODED_LEN: u32 = 146; //We use this as this is what the UI send as length when omnipool swap is executed +const HDX_USD_SPOT_PRICE: f64 = 0.038; //Current HDX price in USD on CoinGecko on 6th Feb, 2024 +pub const ETH_USD_SPOT_PRICE: f64 = 2337.92; //Current HDX price in USD on CoinGecko on 6th Feb, 2024 #[test] fn min_swap_fee() { @@ -36,15 +38,15 @@ fn min_swap_fee() { let info = call.get_dispatch_info(); let info_len = 146; let fee = TransactionPayment::compute_fee(info_len, &info, 0); - let fee_in_cent = FixedU128::from(fee * HDX_USD_SPOT_PRICE_IN_CENTS).div(UNITS.into()); + let fee_in_cent = FixedU128::from_float(fee as f64 * HDX_USD_SPOT_PRICE).div(UNITS.into()); let tolerance = FixedU128::from((2, (UNITS / 10_000))); println!("Swap tx fee in cents: {fee_in_cent:?}"); assert_eq_approx!( fee_in_cent, - FixedU128::from_float(1.043141719216000000), + FixedU128::from_float(0.009909846329778000), tolerance, - "The min fee should be ~1 cent (0.01$)" + "The min fee should be ~0.01$ (1 cent)" ); }); } @@ -67,11 +69,11 @@ fn max_swap_fee() { let info = call.get_dispatch_info(); let info_len = 146; //We use this as this is what the UI send as length when omnipool swap is executed let fee = TransactionPayment::compute_fee(info_len, &info, 0); - let fee_in_cent = FixedU128::from(fee * HDX_USD_SPOT_PRICE_IN_CENTS).div(UNITS.into()); + let fee_in_cent = FixedU128::from_float(fee as f64 * HDX_USD_SPOT_PRICE).div(UNITS.into()); let tolerance = FixedU128::from((2, (UNITS / 10_000))); assert_eq_approx!( fee_in_cent, - FixedU128::from_float(1006.390180650782000000), + FixedU128::from_float(10.008401718494404694), tolerance, "The max fee should be ~1000 cent (10$)" ); @@ -158,8 +160,9 @@ fn fee_growth_simulator_with_idle_chain() { }); } use pallet_evm::FeeCalculator; + #[test] -fn substrate_evm_free_growth_simulator_with_idle_chain() { +fn substrate_and_evm_fee_growth_simulator_with_idle_chain() { TestNet::reset(); Hydra::execute_with(|| { @@ -183,7 +186,7 @@ fn substrate_evm_free_growth_simulator_with_idle_chain() { let mut nonce = 0; - for b in 2..3 { + for b in 2..HOURS { //=HOURS { hydradx_run_to_block(b); hydradx_runtime::System::set_block_consumed_resources(block_weight, 0); @@ -199,15 +202,14 @@ fn substrate_evm_free_growth_simulator_with_idle_chain() { let fee = TransactionPayment::compute_fee(SWAP_ENCODED_LEN, &info, 0); //let fee_in_cent = FixedU128::from(fee * HDX_USD_SPOT_PRICE_IN_CENTS).div(UNITS.into()); //let fee_in_cent = (fee * HDX_USD_SPOT_PRICE_IN_CENTS) as f64 / 1000000000000.0; - let hdx_usd_spot_price = 0.02; - let fee_in_cent = (fee as f64 * hdx_usd_spot_price) as f64 / 1000000000000.0; + let fee_in_cent = (fee as f64 * HDX_USD_SPOT_PRICE) as f64 / 1000000000000.0; let fee_in_cent = round(fee_in_cent); - let evm_fee_in_cent = get_evm_fee_in_cent(nonce); + let evm_fee_in_cent = round(get_evm_fee_in_cent(nonce)); let next = TransactionPayment::next_fee_multiplier(); - let gas_price = hydradx_runtime::evm::PolynomialGasPrice::min_gas_price(); + let gas_price = hydradx_runtime::evm::FixedGasPrice::min_gas_price(); println!("{b:?} - fee: ${fee_in_cent:?} - evm_fee: ${evm_fee_in_cent:?} - multiplier: {next:?} - gas {gas_price:?}"); nonce = nonce + 1; @@ -216,7 +218,7 @@ fn substrate_evm_free_growth_simulator_with_idle_chain() { } fn round(fee_in_cent: f64) -> f64 { - let decimal_places = 3; + let decimal_places = 6; let rounder = 10_f64.powi(decimal_places); (fee_in_cent * rounder).round() / rounder } diff --git a/integration-tests/src/non_native_fee.rs b/integration-tests/src/non_native_fee.rs index d6b72cf00..83c64fec6 100644 --- a/integration-tests/src/non_native_fee.rs +++ b/integration-tests/src/non_native_fee.rs @@ -46,7 +46,7 @@ fn non_native_fee_payment_works_with_oracle_price_based_on_onchain_route() { ) ); let bob_balance = hydradx_runtime::Tokens::free_balance(BTC, &AccountId::from(BOB)); - assert_eq!(bob_balance, 999988); + assert_eq!(bob_balance, 999994); assert_ok!(hydradx_runtime::Balances::force_set_balance( hydradx_runtime::RuntimeOrigin::root(), @@ -76,7 +76,7 @@ fn non_native_fee_payment_works_with_oracle_price_based_on_onchain_route() { let dave_balance = hydradx_runtime::Tokens::free_balance(DAI, &AccountId::from(DAVE)); //TODO: something is off here, maybe no onchain route, or so, check it out - assert_eq!(dave_balance, 999_997_454_879_274_132_400); //Price based on oracle with onchain route + assert_eq!(dave_balance, 999_998_727_439_637_199_700); //Price based on oracle with onchain route }); } diff --git a/integration-tests/src/oracle.rs b/integration-tests/src/oracle.rs index 1480f04f4..5a668548b 100644 --- a/integration-tests/src/oracle.rs +++ b/integration-tests/src/oracle.rs @@ -29,6 +29,7 @@ pub fn hydradx_run_to_block(to: BlockNumber) { hydradx_runtime::System::on_initialize(b + 1); hydradx_runtime::EmaOracle::on_initialize(b + 1); + hydradx_runtime::DynamicEvmFee::on_initialize(b + 1); hydradx_runtime::System::set_block_number(b + 1); } diff --git a/integration-tests/src/polkadot_test_net.rs b/integration-tests/src/polkadot_test_net.rs index 060c9ed0f..abe4778a8 100644 --- a/integration-tests/src/polkadot_test_net.rs +++ b/integration-tests/src/polkadot_test_net.rs @@ -451,7 +451,7 @@ pub mod hydra { (DAI, Price::from(1)), (ACA, Price::from(1)), (BTC, Price::from_inner(134_000_000)), - (WETH, Price::from_inner(3_666_754_716_981_130_000)), + (WETH, pallet_dynamic_evm_fee::HDX_ETH_PRICE), ], account_currencies: vec![], }, @@ -598,6 +598,7 @@ pub fn polkadot_run_to_block(to: BlockNumber) { hydradx_runtime::EmaOracle::on_initialize(b + 1); hydradx_runtime::DCA::on_initialize(b + 1); hydradx_runtime::CircuitBreaker::on_initialize(b + 1); + hydradx_runtime::DynamicEvmFee::on_initialize(b + 1); hydradx_runtime::System::set_block_number(b + 1); } diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 4db3d5106..dbf5863cc 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -20,7 +20,7 @@ #[cfg(test)] mod tests; -mod types; +pub mod types; // Re-export pallet items so that they can be accessed from the crate namespace. pub use pallet::*; @@ -40,6 +40,8 @@ use sp_runtime::FixedU128; use sp_runtime::Permill; use sp_runtime::Saturating; +pub const ETH_HDX_REFERENCE_PRICE: FixedU128 = FixedU128::from_inner(16420844565569051996); //Current onchain ETH price on at block 4418935 + #[frame_support::pallet] pub mod pallet { use crate::*; @@ -65,7 +67,7 @@ pub mod pallet { type Multiplier: MultiplierProvider; /// Native price oracle - type NativePriceOracle: NativePriceOracle; + type NativePriceOracle: NativePriceOracle; /// Eth Asset #[pallet::constant] @@ -92,6 +94,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(_: BlockNumberFor) -> Weight { + //TODO: add a integration test BaseFeePerGas::::mutate(|old_base_fee_per_gas| { let min_gas_price = T::DefaultBaseFeePerGas::get().saturating_div(10); let max_gas_price = 17304992000u128; //TODO: make it constant @@ -102,21 +105,21 @@ pub mod pallet { .saturating_mul_int(T::DefaultBaseFeePerGas::get()) .saturating_mul(3); - let reference_price = FixedU128::saturating_from_rational(1, 70000); //TODO: - let Some(hdx_eth_price) = T::NativePriceOracle::price(T::WethAssetId::get()) else { + let Some(eth_hdx_price) = T::NativePriceOracle::price(T::WethAssetId::get()) else { log::warn!(target: "runtime::dynamic-evm-fee", "Can not get HDX-ETH price from oracle"); return; }; + let eth_hdx_price = FixedU128::from_rational(eth_hdx_price.n, eth_hdx_price.d); - let (price_diff, hdx_price_increased) = if hdx_eth_price > reference_price { - (hdx_eth_price.saturating_sub(reference_price), true) + let (price_diff, hdx_pumps_against_hdx) = if eth_hdx_price > ETH_HDX_REFERENCE_PRICE { + (eth_hdx_price.saturating_sub(ETH_HDX_REFERENCE_PRICE), false) } else { - (reference_price.saturating_sub(hdx_eth_price), false) + (ETH_HDX_REFERENCE_PRICE.saturating_sub(eth_hdx_price), true) }; let Some(percentage_change) = price_diff .saturating_mul(FixedU128::saturating_from_integer(100)) - .const_checked_div(reference_price) else { + .const_checked_div(ETH_HDX_REFERENCE_PRICE) else { log::warn!(target: "runtime::dynamic-evm-fee", "Can not calculate percentage change"); return; }; @@ -126,7 +129,7 @@ pub mod pallet { let evm_fee_change = percentage_change_permill.mul_floor(new_base_fee_per_gas); - if hdx_price_increased { + if hdx_pumps_against_hdx { new_base_fee_per_gas = new_base_fee_per_gas.saturating_sub(evm_fee_change); } else { new_base_fee_per_gas = new_base_fee_per_gas.saturating_add(evm_fee_change); @@ -148,6 +151,3 @@ pub mod pallet { #[pallet::generate_deposit(pub(crate) fn deposit_event)] pub enum Event {} } - -//#[pallet::call] -//impl Pallet {} diff --git a/pallets/dynamic-evm-fee/src/tests/mock.rs b/pallets/dynamic-evm-fee/src/tests/mock.rs index 4f0f4e712..7fdf5b23d 100644 --- a/pallets/dynamic-evm-fee/src/tests/mock.rs +++ b/pallets/dynamic-evm-fee/src/tests/mock.rs @@ -39,10 +39,9 @@ use pallet_transaction_payment::Multiplier; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, FixedU128, Perbill, + BuildStorage, FixedPointNumber, FixedU128, Perbill, }; use sp_std::cell::RefCell; - pub type AccountId = u64; pub type Balance = u128; pub type AssetId = u32; @@ -67,11 +66,12 @@ pub const HIGH_ED: Balance = 5; const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); const MAX_BLOCK_WEIGHT: Weight = Weight::from_parts(1024, 0); +pub const DEFAULT_ETH_HDX_ORACLE_PRICE: Ratio = Ratio::new(16420844565569051996, FixedU128::DIV); thread_local! { static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::zero()); static MULTIPLIER: RefCell = RefCell::new(Multiplier::from_rational(1,1000)); - static ORACLE_PRICE: RefCell = RefCell::new(FixedU128::from_rational(1, 70000)); + static ETH_HDX_ORACLE_PRICE: RefCell = RefCell::new(DEFAULT_ETH_HDX_ORACLE_PRICE); } type Block = frame_system::mocking::MockBlock; @@ -139,9 +139,9 @@ impl MultiplierProvider for MultiplierProviderMock { pub struct NativePriceOracleMock; -impl NativePriceOracle for NativePriceOracleMock { - fn price(_: AssetId) -> Option { - Some(ORACLE_PRICE.with(|v| *v.borrow())) +impl NativePriceOracle for NativePriceOracleMock { + fn price(_: AssetId) -> Option { + Some(ETH_HDX_ORACLE_PRICE.with(|v| *v.borrow())) } } @@ -320,8 +320,8 @@ pub fn set_multiplier(multiplier: Multiplier) { *v.borrow_mut() = multiplier; }); } -pub fn set_oracle_price(price: FixedU128) { - ORACLE_PRICE.with(|v| { +pub fn set_oracle_price(price: Ratio) { + ETH_HDX_ORACLE_PRICE.with(|v| { *v.borrow_mut() = price; }); } diff --git a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs index 9e2c579aa..6b61450e2 100644 --- a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs +++ b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs @@ -3,9 +3,10 @@ use crate::tests::mock::*; use crate::tests::*; use frame_support::traits::OnInitialize; use hydra_dx_math::ema::EmaPrice; +use hydra_dx_math::types::Ratio; use pallet_transaction_payment::Multiplier; use sp_core::U256; -use sp_runtime::FixedU128; +use sp_runtime::{FixedPointNumber, FixedU128}; #[test] fn should_return_default_base_fee_when_min_multiplier() { @@ -20,7 +21,7 @@ fn should_return_default_base_fee_when_min_multiplier() { #[test] fn should_increase_evm_fee_with_max_multiplier() { ExtBuilder::default().build().execute_with(|| { - set_multiplier(Multiplier::from_rational(320, 1)); + set_multiplier(Multiplier::from_rational(335, 1)); DynamicEvmFee::on_initialize(1); @@ -32,7 +33,10 @@ fn should_increase_evm_fee_with_max_multiplier() { #[test] fn should_decrease_evm_fee_when_hdx_pumping_10percent_against_eth() { ExtBuilder::default().build().execute_with(|| { - set_oracle_price(FixedU128::from_rational(11, 700000)); + set_oracle_price(Ratio::new( + DEFAULT_ETH_HDX_ORACLE_PRICE.n * 90 / 100, + DEFAULT_ETH_HDX_ORACLE_PRICE.d, + )); DynamicEvmFee::on_initialize(1); @@ -44,20 +48,24 @@ fn should_decrease_evm_fee_when_hdx_pumping_10percent_against_eth() { #[test] fn should_decrease_evm_fee_when_hdx_pumping_1percent_against_eth() { ExtBuilder::default().build().execute_with(|| { - set_oracle_price(FixedU128::from_rational(101, 7000000)); - + set_oracle_price(Ratio::new( + DEFAULT_ETH_HDX_ORACLE_PRICE.n * 99 / 100, + DEFAULT_ETH_HDX_ORACLE_PRICE.d, + )); DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(26479225)); + assert_eq!(new_base_fee, U256::from(26479198)); }); } #[test] fn should_increase_evm_fee_when_hdx_dumping_10percent_against_eth() { ExtBuilder::default().build().execute_with(|| { - set_oracle_price(FixedU128::from_rational(9, 700000)); - + set_oracle_price(Ratio::new( + DEFAULT_ETH_HDX_ORACLE_PRICE.n * 110 / 100, + DEFAULT_ETH_HDX_ORACLE_PRICE.d, + )); DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index b958b045e..edfad1eef 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -23,7 +23,7 @@ pub use crate::{ evm::accounts_conversion::{ExtendedAddressMapping, FindAuthorTruncated}, AssetLocation, Aura, NORMAL_DISPATCH_RATIO, }; -use crate::{TreasuryAccount, FEE_DIVIDER}; +use crate::{DCAOraclePeriod, NativeAssetId, TreasuryAccount, FEE_DIVIDER, LRNA}; use frame_support::{ parameter_types, traits::{Defensive, FindAuthor, Imbalance, OnUnbalanced}, @@ -31,16 +31,21 @@ use frame_support::{ ConsensusEngineId, }; use hex_literal::hex; +use hydra_dx_math::ema::EmaPrice; +use hydradx_adapters::{AssetFeeOraclePriceProvider, OraclePriceProvider}; +use hydradx_traits::{AggregatedPriceOracle, NativePriceOracle}; use orml_tokens::CurrencyAdapter; +use pallet_dynamic_evm_fee::types::MultiplierProvider; +use pallet_ema_oracle::OracleError; use pallet_evm::{EnsureAddressTruncated, FeeCalculator}; use pallet_transaction_multi_payment::{DepositAll, DepositFee, TransferEvmFees}; +use pallet_transaction_payment::Multiplier; use polkadot_xcm::{ latest::MultiLocation, prelude::{AccountKey20, PalletInstance, Parachain, X3}, }; -use primitives::{constants::chain::MAXIMUM_BLOCK_WEIGHT, AccountId, AssetId}; +use primitives::{constants::chain::MAXIMUM_BLOCK_WEIGHT, AccountId, AssetId, BlockNumber}; use sp_core::{Get, U256}; - mod accounts_conversion; pub mod precompiles; @@ -53,9 +58,8 @@ pub const GAS_PER_SECOND: u64 = 40_000_000; // Approximate ratio of the amount of Weight per Gas. const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; -// Fixed gas price of 0.08 gwei per gas, but also divided with the fee divider as HDX price is high atm (~0.02ï¿ ) -// TODO: pallet-base-fee to be implemented after migration to polkadot-v1.1.0 -const DEFAULT_BASE_FEE_PER_GAS: u128 = 80_000_000 / FEE_DIVIDER; +// Fixed gas price of 0.019 gwei per gas +pub const DEFAULT_BASE_FEE_PER_GAS: u128 = 19_000_000; parameter_types! { // We allow for a 75% fullness of a 0.5s block @@ -93,6 +97,7 @@ impl Get for WethAssetId { type WethCurrency = CurrencyAdapter; use frame_support::traits::Currency as PalletCurrency; +use sp_runtime::{FixedU128, Permill}; type NegativeImbalance = >::NegativeImbalance; @@ -108,14 +113,103 @@ impl OnUnbalanced for DealWithFees { } } -pub struct FixedGasPrice; +parameter_types! { + pub PostLogContent: pallet_ethereum::PostLogContent = pallet_ethereum::PostLogContent::BlockAndTxnHashes; +} +use frame_support::weights::FeePolynomial; +use frame_support::weights::WeightToFee; +use frame_support::weights::WeightToFeePolynomial; +use sp_runtime::FixedPointNumber; + +pub struct FixedGasPrice; //TODO: rename to DynamicGasPrice impl FeeCalculator for FixedGasPrice { fn min_gas_price() -> (U256, Weight) { // Return some meaningful gas price and weight - (DEFAULT_BASE_FEE_PER_GAS.into(), Weight::from_parts(7u64, 0)) + let base_fee_per_gas = crate::DynamicEvmFee::base_evm_fee(); + (base_fee_per_gas.into(), Weight::from_parts(7u64, 0)) //TODO: add the weight once benchmarked + } +} + +pub struct TransactionPaymentMultiplier; + +impl MultiplierProvider for TransactionPaymentMultiplier { + fn next() -> Multiplier { + crate::TransactionPayment::next_fee_multiplier() + } +} + +/*pub trait MultiplierProvider { + fn next() -> Multiplier; +}*/ + +/* +pub struct PolynomialGasPrice; + +pub struct GasPriceCalc( + sp_std::marker::PhantomData<(MP, AggregatedPriceGetter, Weth)>, +); + +impl FeeCalculator for GasPriceCalc +where + MP: MultiplierProvider, + AggregatedPriceGetter: NativePriceOracle, + Weth: Get, +{ + fn min_gas_price() -> (U256, Weight) { + //TODO: add steps how much it can change? + //TODO: add min and max range?! + //TODO: migration for multiplier? + let mut multiplier = crate::TransactionPayment::next_fee_multiplier(); + + let max_gas_price = 17304992000; + + let bfpg = DEFAULT_BASE_FEE_PER_GAS + + multiplier + .saturating_mul_int(DEFAULT_BASE_FEE_PER_GAS) + .saturating_mul(3); + + let bfpg = bfpg.clamp(DEFAULT_BASE_FEE_PER_GAS, max_gas_price); //TODO: is there some minimum price we want + + (bfpg.into(), Weight::from_parts(u64::MAX, 0)) + } +} + + + +impl FeeCalculator for PolynomialGasPrice { + fn min_gas_price() -> (U256, Weight) { + //TODO: add steps how much it can change? + //TODO: add min and max range?! + //TODO: migration for multiplier? + let mut multiplier = crate::TransactionPayment::next_fee_multiplier(); + + let max_gas_price = 17304992000; + + let bfpg = DEFAULT_BASE_FEE_PER_GAS + + multiplier + .saturating_mul_int(DEFAULT_BASE_FEE_PER_GAS) + .saturating_mul(3); + + let bfpg = bfpg.clamp(DEFAULT_BASE_FEE_PER_GAS, max_gas_price); //TODO: is there some minimum price we want + + (bfpg.into(), Weight::from_parts(u64::MAX, 0)) } } +fn calculate_polynomial(multiplier: Multiplier) -> FixedU128 { + let degree = 2; // You can adjust the degree to control the growth rate. + let coefficients: [FixedU128; 3] = [FixedU128::from_u32(0), FixedU128::from_u32(1), FixedU128::from_u32(2)]; + + let mut result = FixedU128::from_u32(0); + let mut power_x = FixedU128::from_u32(1); + + for i in 0..=degree { + result = result + (coefficients[i] * power_x); + power_x = power_x * multiplier; + } + + result +}*/ parameter_types! { /// The amount of gas per pov. A ratio of 4 if we convert ref_time to gas and we compare /// it with the pov_size for a block. E.g. @@ -128,6 +222,7 @@ parameter_types! { pub GasLimitStorageGrowthRatio: u64 = 366; } +//TODO: check if we need to plug the base fee in better way. How does elasticity work? impl pallet_evm::Config for crate::Runtime { type AddressMapping = ExtendedAddressMapping; type BlockGasLimit = BlockGasLimit; @@ -136,6 +231,7 @@ impl pallet_evm::Config for crate::Runtime { type ChainId = crate::EVMChainId; type Currency = WethCurrency; type FeeCalculator = FixedGasPrice; + //type FeeCalculator = crate::BaseFee; type FindAuthor = FindAuthorTruncated; type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type OnChargeTransaction = TransferEvmFees; @@ -154,13 +250,29 @@ impl pallet_evm::Config for crate::Runtime { impl pallet_evm_chain_id::Config for crate::Runtime {} -parameter_types! { - pub PostLogContent: pallet_ethereum::PostLogContent = pallet_ethereum::PostLogContent::BlockAndTxnHashes; -} - impl pallet_ethereum::Config for crate::Runtime { type RuntimeEvent = crate::RuntimeEvent; type StateRoot = pallet_ethereum::IntermediateStateRoot; type PostLogContent = PostLogContent; type ExtraDataLength = sp_core::ConstU32<1>; } + +parameter_types! { + pub const DefaultBaseFeePerGas: u128 = DEFAULT_BASE_FEE_PER_GAS; +} + +impl pallet_dynamic_evm_fee::Config for crate::Runtime { + type RuntimeEvent = crate::RuntimeEvent; + type AssetId = AssetId; + type DefaultBaseFeePerGas = DefaultBaseFeePerGas; + type Multiplier = TransactionPaymentMultiplier; + type NativePriceOracle = AssetFeeOraclePriceProvider< + NativeAssetId, + crate::MultiTransactionPayment, + crate::Router, + OraclePriceProvider, + crate::MultiTransactionPayment, + DCAOraclePeriod, + >; + type WethAssetId = WethAssetId; +} diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 6bc8956b5..3a1a8dbe7 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -185,6 +185,7 @@ construct_runtime!( EVM: pallet_evm = 90, EVMChainId: pallet_evm_chain_id = 91, Ethereum: pallet_ethereum = 92, + DynamicEvmFee: pallet_dynamic_evm_fee = 93, // Parachain ParachainSystem: cumulus_pallet_parachain_system exclude_parts { Config } = 103, diff --git a/runtime/hydradx/src/system.rs b/runtime/hydradx/src/system.rs index b896e638f..db98202ba 100644 --- a/runtime/hydradx/src/system.rs +++ b/runtime/hydradx/src/system.rs @@ -420,8 +420,8 @@ pub type SlowAdjustingFeeUpdate = pub struct WeightToFee; -pub const FEE_DIVIDER: u128 = 3; // We use this to divide fee related constant as HDX price is high (~0.02$), but we want to reduce the fee price - //TODO: make constant for fee related stuff +//TODO: make constants for all fee related stuff +pub const FEE_DIVIDER: u128 = 6; // We use this to divide fee related constant as HDX price is high (~0.04$), but we want to reduce the fee price impl WeightToFeePolynomial for WeightToFee { type Balance = Balance; @@ -459,9 +459,9 @@ parameter_types! { pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(10, 113); /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure /// that combined with `AdjustmentVariable`, we can recover from the minimum. - pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); + pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1000u128); /// The maximum amount of the multiplier. - pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(320); + pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(335); } impl pallet_transaction_payment::Config for Runtime { From feb02ac6169ba4f704cfeb3559ae67ead5dfb0e0 Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 6 Feb 2024 14:12:21 +0100 Subject: [PATCH 19/64] cleaning up --- pallets/dynamic-evm-fee/src/lib.rs | 15 ++--- pallets/dynamic-evm-fee/src/tests/mock.rs | 55 ++----------------- .../src/tests/on_initialize.rs | 3 - 3 files changed, 10 insertions(+), 63 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index dbf5863cc..af3d2419b 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -28,19 +28,17 @@ pub use pallet::*; use crate::types::MultiplierProvider; use codec::HasCompact; use frame_support::pallet_prelude::*; -use frame_support::sp_runtime::traits::BlockNumberProvider; use frame_system::pallet_prelude::BlockNumberFor; use hydra_dx_math::ema::EmaPrice; use hydradx_traits::NativePriceOracle; -use primitives::BlockNumber; use sp_core::U256; use sp_runtime::FixedPointNumber; -use sp_runtime::FixedPointOperand; use sp_runtime::FixedU128; use sp_runtime::Permill; use sp_runtime::Saturating; pub const ETH_HDX_REFERENCE_PRICE: FixedU128 = FixedU128::from_inner(16420844565569051996); //Current onchain ETH price on at block 4418935 +pub const MAX_BASE_FEE_PER_GAS: u128 = 17304992000u128; #[frame_support::pallet] pub mod pallet { @@ -96,9 +94,8 @@ pub mod pallet { fn on_initialize(_: BlockNumberFor) -> Weight { //TODO: add a integration test BaseFeePerGas::::mutate(|old_base_fee_per_gas| { - let min_gas_price = T::DefaultBaseFeePerGas::get().saturating_div(10); - let max_gas_price = 17304992000u128; //TODO: make it constant - let mut multiplier = T::Multiplier::next(); + let min_base_fee_per_gas = T::DefaultBaseFeePerGas::get().saturating_div(10); + let multiplier = T::Multiplier::next(); let mut new_base_fee_per_gas = T::DefaultBaseFeePerGas::get() + multiplier @@ -106,7 +103,7 @@ pub mod pallet { .saturating_mul(3); let Some(eth_hdx_price) = T::NativePriceOracle::price(T::WethAssetId::get()) else { - log::warn!(target: "runtime::dynamic-evm-fee", "Can not get HDX-ETH price from oracle"); + log::warn!(target: "runtime::dynamic-evm-fee", "Can not get ETH-HDX price from oracle"); return; }; let eth_hdx_price = FixedU128::from_rational(eth_hdx_price.n, eth_hdx_price.d); @@ -120,7 +117,7 @@ pub mod pallet { let Some(percentage_change) = price_diff .saturating_mul(FixedU128::saturating_from_integer(100)) .const_checked_div(ETH_HDX_REFERENCE_PRICE) else { - log::warn!(target: "runtime::dynamic-evm-fee", "Can not calculate percentage change"); + log::warn!(target: "runtime::dynamic-evm-fee", "Unexpected error: Can not calculate percentage change"); return; }; @@ -135,7 +132,7 @@ pub mod pallet { new_base_fee_per_gas = new_base_fee_per_gas.saturating_add(evm_fee_change); } - new_base_fee_per_gas = new_base_fee_per_gas.clamp(min_gas_price, max_gas_price); + new_base_fee_per_gas = new_base_fee_per_gas.clamp(min_base_fee_per_gas, MAX_BASE_FEE_PER_GAS); *old_base_fee_per_gas = U256::from(new_base_fee_per_gas); }); diff --git a/pallets/dynamic-evm-fee/src/tests/mock.rs b/pallets/dynamic-evm-fee/src/tests/mock.rs index 7fdf5b23d..8c01967f3 100644 --- a/pallets/dynamic-evm-fee/src/tests/mock.rs +++ b/pallets/dynamic-evm-fee/src/tests/mock.rs @@ -15,7 +15,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::*; pub use crate as multi_payment; use crate::Config; use hydra_dx_math::types::Ratio; @@ -23,23 +22,21 @@ use hydra_dx_math::types::Ratio; use crate as dynamic_evm_fee; use crate::types::MultiplierProvider; use frame_support::{ - dispatch::DispatchClass, parameter_types, traits::{Everything, Get, Nothing}, - weights::{IdentityFee, Weight}, + weights::Weight, }; use frame_system as system; use hydra_dx_math::ema::EmaPrice; -use hydradx_traits::router::{RouteProvider, Trade}; -use hydradx_traits::{AssetPairAccountIdFor, NativePriceOracle, OraclePeriod, PriceOracle}; -use orml_traits::currency::MutationHooks; +use hydradx_traits::router::RouteProvider; +use hydradx_traits::NativePriceOracle; use orml_traits::parameter_type_with_key; use pallet_currencies::BasicCurrencyAdapter; use pallet_transaction_payment::Multiplier; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, FixedPointNumber, FixedU128, Perbill, + BuildStorage, FixedPointNumber, FixedU128, }; use sp_std::cell::RefCell; pub type AccountId = u64; @@ -50,22 +47,17 @@ pub type Amount = i128; pub const INITIAL_BALANCE: Balance = 1_000_000_000_000_000u128; pub const ALICE: AccountId = 1; -pub const BOB: AccountId = 2; pub const FEE_RECEIVER: AccountId = 300; pub const HDX: AssetId = 0; pub const WETH: AssetId = 1; pub const SUPPORTED_CURRENCY: AssetId = 2000; pub const SUPPORTED_CURRENCY_WITH_PRICE: AssetId = 3000; -pub const UNSUPPORTED_CURRENCY: AssetId = 4000; -pub const SUPPORTED_CURRENCY_NO_BALANCE: AssetId = 5000; // Used for insufficient balance testing pub const HIGH_ED_CURRENCY: AssetId = 6000; pub const HIGH_VALUE_CURRENCY: AssetId = 7000; pub const HIGH_ED: Balance = 5; -const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -const MAX_BLOCK_WEIGHT: Weight = Weight::from_parts(1024, 0); pub const DEFAULT_ETH_HDX_ORACLE_PRICE: Ratio = Ratio::new(16420844565569051996, FixedU128::DIV); thread_local! { @@ -167,20 +159,6 @@ pub struct DefaultRouteProvider; impl RouteProvider for DefaultRouteProvider {} -pub struct PriceProviderMock {} - -impl PriceOracle for PriceProviderMock { - type Price = Ratio; - - fn price(route: &[Trade], _period: OraclePeriod) -> Option { - let asset_a = route.first().unwrap().asset_in; - let asset_b = route.first().unwrap().asset_out; - match (asset_a, asset_b) { - (SUPPORTED_CURRENCY_WITH_PRICE, HDX) => Some(Ratio::new(1, 10)), - _ => None, - } - } -} impl pallet_balances::Config for Test { type MaxLocks = MaxLocks; /// The type for recording an account's balance. @@ -238,7 +216,6 @@ pub struct ExtBuilder { base_weight: Weight, native_balances: Vec<(AccountId, Balance)>, endowed_accounts: Vec<(AccountId, AssetId, Balance)>, - account_currencies: Vec<(AccountId, AssetId)>, } impl Default for ExtBuilder { @@ -251,35 +228,15 @@ impl Default for ExtBuilder { (ALICE, SUPPORTED_CURRENCY, INITIAL_BALANCE), // used for fallback price test (ALICE, SUPPORTED_CURRENCY_WITH_PRICE, INITIAL_BALANCE), ], - - account_currencies: vec![], } } } impl ExtBuilder { - pub fn base_weight(mut self, base_weight: u64) -> Self { - self.base_weight = Weight::from_parts(base_weight, 0); - self - } - pub fn account_native_balance(mut self, account: AccountId, balance: Balance) -> Self { - self.native_balances.push((account, balance)); - self - } - pub fn account_tokens(mut self, account: AccountId, asset: AssetId, balance: Balance) -> Self { - self.endowed_accounts.push((account, asset, balance)); - self - } - pub fn with_currencies(mut self, account_currencies: Vec<(AccountId, AssetId)>) -> Self { - self.account_currencies = account_currencies; - self - } fn set_constants(&self) { EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight); } pub fn build(self) -> sp_io::TestExternalities { - use frame_support::traits::OnInitialize; - self.set_constants(); let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); @@ -311,10 +268,6 @@ impl ExtBuilder { } } -pub fn expect_events(e: Vec) { - test_utils::expect_events::(e); -} - pub fn set_multiplier(multiplier: Multiplier) { MULTIPLIER.with(|v| { *v.borrow_mut() = multiplier; diff --git a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs index 6b61450e2..9691e4942 100644 --- a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs +++ b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs @@ -1,12 +1,9 @@ use crate::tests::mock::DynamicEvmFee; use crate::tests::mock::*; -use crate::tests::*; use frame_support::traits::OnInitialize; -use hydra_dx_math::ema::EmaPrice; use hydra_dx_math::types::Ratio; use pallet_transaction_payment::Multiplier; use sp_core::U256; -use sp_runtime::{FixedPointNumber, FixedU128}; #[test] fn should_return_default_base_fee_when_min_multiplier() { From b7fb154558839715599e5eeada5069f9f1e7e7a0 Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 6 Feb 2024 14:31:50 +0100 Subject: [PATCH 20/64] refactoring --- Cargo.lock | 1 + integration-tests/src/evm.rs | 6 +- integration-tests/src/fee_calculation.rs | 2 +- integration-tests/src/polkadot_test_net.rs | 2 +- pallets/dynamic-evm-fee/Cargo.toml | 3 + pallets/dynamic-evm-fee/README.md | 6 +- pallets/dynamic-evm-fee/src/lib.rs | 22 +++-- pallets/dynamic-evm-fee/src/tests/mock.rs | 1 - runtime/hydradx/src/evm/mod.rs | 93 ++-------------------- 9 files changed, 25 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04f9547a9..46b200388 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7476,6 +7476,7 @@ dependencies = [ "orml-traits", "pallet-balances", "pallet-currencies", + "pallet-evm", "pallet-transaction-payment", "parity-scale-codec", "primitives", diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index ace8487ee..26df2fd62 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -5,7 +5,6 @@ use fp_evm::{Context, Transfer}; 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::FixedGasPrice; use hydradx_runtime::{ evm::precompiles::{ addr, @@ -21,7 +20,6 @@ use pretty_assertions::assert_eq; use sp_core::{blake2_256, H160, H256, U256}; use sp_runtime::{traits::SignedExtension, FixedU128, Permill}; use std::borrow::Cow; -use std::ops::Div; use xcm_emulator::TestExt; pub const TREASURY_ACCOUNT_INIT_BALANCE: Balance = 1000 * UNITS; @@ -650,7 +648,7 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { }); let gas_limit = 1000000; - let gas_price = FixedGasPrice::min_gas_price(); + let gas_price = hydradx_runtime::DynamicEvmFee::min_gas_price(); //Execute omnipool via EVM assert_ok!(EVM::call( @@ -716,7 +714,7 @@ pub fn get_evm_fee_in_cent(nonce: u128) -> f64 { let gas_limit = 1000000; - let gas_price = FixedGasPrice::min_gas_price(); + let gas_price = hydradx_runtime::DynamicEvmFee::min_gas_price(); //Execute omnipool via EVM assert_ok!(EVM::call( evm_signed_origin(evm_address()), diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs index 22afdba0d..e7b310cbb 100644 --- a/integration-tests/src/fee_calculation.rs +++ b/integration-tests/src/fee_calculation.rs @@ -209,7 +209,7 @@ fn substrate_and_evm_fee_growth_simulator_with_idle_chain() { let evm_fee_in_cent = round(get_evm_fee_in_cent(nonce)); let next = TransactionPayment::next_fee_multiplier(); - let gas_price = hydradx_runtime::evm::FixedGasPrice::min_gas_price(); + let gas_price = hydradx_runtime::DynamicEvmFee::min_gas_price(); println!("{b:?} - fee: ${fee_in_cent:?} - evm_fee: ${evm_fee_in_cent:?} - multiplier: {next:?} - gas {gas_price:?}"); nonce = nonce + 1; diff --git a/integration-tests/src/polkadot_test_net.rs b/integration-tests/src/polkadot_test_net.rs index abe4778a8..8d859df6a 100644 --- a/integration-tests/src/polkadot_test_net.rs +++ b/integration-tests/src/polkadot_test_net.rs @@ -451,7 +451,7 @@ pub mod hydra { (DAI, Price::from(1)), (ACA, Price::from(1)), (BTC, Price::from_inner(134_000_000)), - (WETH, pallet_dynamic_evm_fee::HDX_ETH_PRICE), + (WETH, pallet_dynamic_evm_fee::ETH_HDX_REFERENCE_PRICE), ], account_currencies: vec![], }, diff --git a/pallets/dynamic-evm-fee/Cargo.toml b/pallets/dynamic-evm-fee/Cargo.toml index 0b7889fff..117f74e7a 100644 --- a/pallets/dynamic-evm-fee/Cargo.toml +++ b/pallets/dynamic-evm-fee/Cargo.toml @@ -32,6 +32,9 @@ sp-std = { workspace = true } sp-runtime = { workspace = true } sp-io = { workspace = true } +# Evm dependencies +pallet-evm = { workspace = true } + [dev-dependencies] pallet-currencies = { workspace = true } orml-tokens = { workspace = true, features=["std"] } diff --git a/pallets/dynamic-evm-fee/README.md b/pallets/dynamic-evm-fee/README.md index d3d938873..2c8924a2e 100644 --- a/pallets/dynamic-evm-fee/README.md +++ b/pallets/dynamic-evm-fee/README.md @@ -1,5 +1 @@ -# Relaychain info pallet - -Support pallet for a parachain. Includes various little feaures features realted to relay chain - -- Emits `Initialized` event in on_initialize pallet's method with informaton of current parachain block and current relay chain block. +# TODO: add readme \ No newline at end of file diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index af3d2419b..fbc4cba56 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -46,8 +46,6 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Identifier for the class of asset. type AssetId: Member + Parameter @@ -67,7 +65,7 @@ pub mod pallet { /// Native price oracle type NativePriceOracle: NativePriceOracle; - /// Eth Asset + /// Eth Asset Id #[pallet::constant] type WethAssetId: Get; } @@ -84,7 +82,7 @@ pub mod pallet { U256::from(T::DefaultBaseFeePerGas::get()) } - /// Base Evm Fee + /// Base fee per gas #[pallet::storage] #[pallet::getter(fn base_evm_fee)] pub type BaseFeePerGas = StorageValue<_, U256, ValueQuery, DefaultBaseFeePerGas>; @@ -92,7 +90,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(_: BlockNumberFor) -> Weight { - //TODO: add a integration test + //TODO: add a integration test with price change from trades so oracle price changes BaseFeePerGas::::mutate(|old_base_fee_per_gas| { let min_base_fee_per_gas = T::DefaultBaseFeePerGas::get().saturating_div(10); let multiplier = T::Multiplier::next(); @@ -140,11 +138,11 @@ pub mod pallet { Weight::default() //TODO: benchmark } } - - #[pallet::error] - pub enum Error {} - - #[pallet::event] - #[pallet::generate_deposit(pub(crate) fn deposit_event)] - pub enum Event {} +} +impl pallet_evm::FeeCalculator for Pallet { + fn min_gas_price() -> (U256, Weight) { + // Return some meaningful gas price and weight + let base_fee_per_gas = Self::base_evm_fee(); + (base_fee_per_gas.into(), Weight::from_parts(7u64, 0)) //TODO: add the weight once benchmarked + } } diff --git a/pallets/dynamic-evm-fee/src/tests/mock.rs b/pallets/dynamic-evm-fee/src/tests/mock.rs index 8c01967f3..e8a32e828 100644 --- a/pallets/dynamic-evm-fee/src/tests/mock.rs +++ b/pallets/dynamic-evm-fee/src/tests/mock.rs @@ -146,7 +146,6 @@ impl Get for DefaultBaseDFeePerGas { } impl Config for Test { - type RuntimeEvent = RuntimeEvent; type AssetId = AssetId; type DefaultBaseFeePerGas = DefaultBaseDFeePerGas; type Multiplier = MultiplierProviderMock; diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index edfad1eef..347c7093e 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -23,7 +23,7 @@ pub use crate::{ evm::accounts_conversion::{ExtendedAddressMapping, FindAuthorTruncated}, AssetLocation, Aura, NORMAL_DISPATCH_RATIO, }; -use crate::{DCAOraclePeriod, NativeAssetId, TreasuryAccount, FEE_DIVIDER, LRNA}; +use crate::{DCAOraclePeriod, NativeAssetId, TreasuryAccount, LRNA}; use frame_support::{ parameter_types, traits::{Defensive, FindAuthor, Imbalance, OnUnbalanced}, @@ -31,20 +31,17 @@ use frame_support::{ ConsensusEngineId, }; use hex_literal::hex; -use hydra_dx_math::ema::EmaPrice; use hydradx_adapters::{AssetFeeOraclePriceProvider, OraclePriceProvider}; -use hydradx_traits::{AggregatedPriceOracle, NativePriceOracle}; use orml_tokens::CurrencyAdapter; use pallet_dynamic_evm_fee::types::MultiplierProvider; -use pallet_ema_oracle::OracleError; -use pallet_evm::{EnsureAddressTruncated, FeeCalculator}; +use pallet_evm::EnsureAddressTruncated; use pallet_transaction_multi_payment::{DepositAll, DepositFee, TransferEvmFees}; use pallet_transaction_payment::Multiplier; use polkadot_xcm::{ latest::MultiLocation, prelude::{AccountKey20, PalletInstance, Parachain, X3}, }; -use primitives::{constants::chain::MAXIMUM_BLOCK_WEIGHT, AccountId, AssetId, BlockNumber}; +use primitives::{constants::chain::MAXIMUM_BLOCK_WEIGHT, AccountId, AssetId}; use sp_core::{Get, U256}; mod accounts_conversion; pub mod precompiles; @@ -97,7 +94,6 @@ impl Get for WethAssetId { type WethCurrency = CurrencyAdapter; use frame_support::traits::Currency as PalletCurrency; -use sp_runtime::{FixedU128, Permill}; type NegativeImbalance = >::NegativeImbalance; @@ -116,11 +112,8 @@ impl OnUnbalanced for DealWithFees { parameter_types! { pub PostLogContent: pallet_ethereum::PostLogContent = pallet_ethereum::PostLogContent::BlockAndTxnHashes; } -use frame_support::weights::FeePolynomial; -use frame_support::weights::WeightToFee; -use frame_support::weights::WeightToFeePolynomial; -use sp_runtime::FixedPointNumber; +/* pub struct FixedGasPrice; //TODO: rename to DynamicGasPrice impl FeeCalculator for FixedGasPrice { fn min_gas_price() -> (U256, Weight) { @@ -128,7 +121,7 @@ impl FeeCalculator for FixedGasPrice { let base_fee_per_gas = crate::DynamicEvmFee::base_evm_fee(); (base_fee_per_gas.into(), Weight::from_parts(7u64, 0)) //TODO: add the weight once benchmarked } -} +}*/ pub struct TransactionPaymentMultiplier; @@ -138,78 +131,6 @@ impl MultiplierProvider for TransactionPaymentMultiplier { } } -/*pub trait MultiplierProvider { - fn next() -> Multiplier; -}*/ - -/* -pub struct PolynomialGasPrice; - -pub struct GasPriceCalc( - sp_std::marker::PhantomData<(MP, AggregatedPriceGetter, Weth)>, -); - -impl FeeCalculator for GasPriceCalc -where - MP: MultiplierProvider, - AggregatedPriceGetter: NativePriceOracle, - Weth: Get, -{ - fn min_gas_price() -> (U256, Weight) { - //TODO: add steps how much it can change? - //TODO: add min and max range?! - //TODO: migration for multiplier? - let mut multiplier = crate::TransactionPayment::next_fee_multiplier(); - - let max_gas_price = 17304992000; - - let bfpg = DEFAULT_BASE_FEE_PER_GAS - + multiplier - .saturating_mul_int(DEFAULT_BASE_FEE_PER_GAS) - .saturating_mul(3); - - let bfpg = bfpg.clamp(DEFAULT_BASE_FEE_PER_GAS, max_gas_price); //TODO: is there some minimum price we want - - (bfpg.into(), Weight::from_parts(u64::MAX, 0)) - } -} - - - -impl FeeCalculator for PolynomialGasPrice { - fn min_gas_price() -> (U256, Weight) { - //TODO: add steps how much it can change? - //TODO: add min and max range?! - //TODO: migration for multiplier? - let mut multiplier = crate::TransactionPayment::next_fee_multiplier(); - - let max_gas_price = 17304992000; - - let bfpg = DEFAULT_BASE_FEE_PER_GAS - + multiplier - .saturating_mul_int(DEFAULT_BASE_FEE_PER_GAS) - .saturating_mul(3); - - let bfpg = bfpg.clamp(DEFAULT_BASE_FEE_PER_GAS, max_gas_price); //TODO: is there some minimum price we want - - (bfpg.into(), Weight::from_parts(u64::MAX, 0)) - } -} - -fn calculate_polynomial(multiplier: Multiplier) -> FixedU128 { - let degree = 2; // You can adjust the degree to control the growth rate. - let coefficients: [FixedU128; 3] = [FixedU128::from_u32(0), FixedU128::from_u32(1), FixedU128::from_u32(2)]; - - let mut result = FixedU128::from_u32(0); - let mut power_x = FixedU128::from_u32(1); - - for i in 0..=degree { - result = result + (coefficients[i] * power_x); - power_x = power_x * multiplier; - } - - result -}*/ parameter_types! { /// The amount of gas per pov. A ratio of 4 if we convert ref_time to gas and we compare /// it with the pov_size for a block. E.g. @@ -222,7 +143,6 @@ parameter_types! { pub GasLimitStorageGrowthRatio: u64 = 366; } -//TODO: check if we need to plug the base fee in better way. How does elasticity work? impl pallet_evm::Config for crate::Runtime { type AddressMapping = ExtendedAddressMapping; type BlockGasLimit = BlockGasLimit; @@ -230,7 +150,7 @@ impl pallet_evm::Config for crate::Runtime { type CallOrigin = EnsureAddressTruncated; type ChainId = crate::EVMChainId; type Currency = WethCurrency; - type FeeCalculator = FixedGasPrice; + type FeeCalculator = crate::DynamicEvmFee; //type FeeCalculator = crate::BaseFee; type FindAuthor = FindAuthorTruncated; type GasWeightMapping = pallet_evm::FixedGasWeightMapping; @@ -262,7 +182,6 @@ parameter_types! { } impl pallet_dynamic_evm_fee::Config for crate::Runtime { - type RuntimeEvent = crate::RuntimeEvent; type AssetId = AssetId; type DefaultBaseFeePerGas = DefaultBaseFeePerGas; type Multiplier = TransactionPaymentMultiplier; From e5a056978c431fb7feb8fe189f907b4c490c4158 Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 6 Feb 2024 14:51:23 +0100 Subject: [PATCH 21/64] refactoring in tests --- integration-tests/src/evm.rs | 41 ------------------------ integration-tests/src/fee_calculation.rs | 41 ++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index 26df2fd62..55fdcf959 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -700,47 +700,6 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { assert!(relative_fee_difference < tolerated_fee_difference); }) } -use crate::fee_calculation::ETH_USD_SPOT_PRICE; -//TODO: replace this -pub fn get_evm_fee_in_cent(nonce: u128) -> f64 { - let treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); - - let omni_sell = hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { - asset_in: HDX, - asset_out: DAI, - amount: UNITS, - 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( - evm_signed_origin(evm_address()), - evm_address(), - DISPATCH_ADDR, - omni_sell.encode(), - U256::from(0), - gas_limit, - gas_price.0 * 10, - None, - Some(U256::from(nonce)), - [].into(), - )); - - let new_treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); - let fee_weth_evm = new_treasury_eth_balance - treasury_eth_balance; - - let fee_in_cents = ETH_USD_SPOT_PRICE * fee_weth_evm as f64 / 1000000000000000000.0; - round(fee_in_cents) -} - -fn round(fee_in_cent: f64) -> f64 { - let decimal_places = 20; - let rounder = 10_f64.powi(decimal_places); - (fee_in_cent * rounder).round() / rounder -} pub fn init_omnipool_with_oracle_for_block_10() { init_omnipol(); diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs index e7b310cbb..f6f05f221 100644 --- a/integration-tests/src/fee_calculation.rs +++ b/integration-tests/src/fee_calculation.rs @@ -1,13 +1,19 @@ #![cfg(test)] +use crate::evm::DISPATCH_ADDR; use crate::{oracle::hydradx_run_to_block, polkadot_test_net::*}; use frame_support::assert_ok; use frame_support::dispatch::DispatchClass; use frame_support::dispatch::GetDispatchInfo; +use hydradx_runtime::Tokens; use hydradx_runtime::TransactionPayment; +use hydradx_runtime::EVM; +use orml_traits::MultiCurrency; use primitives::constants::currency::UNITS; use primitives::constants::time::HOURS; use primitives::{AssetId, Balance}; +use sp_core::Encode; +use sp_core::U256; use sp_runtime::{FixedU128, Permill}; use test_utils::assert_eq_approx; use xcm_emulator::TestExt; @@ -80,8 +86,6 @@ fn max_swap_fee() { }); } -use crate::evm::get_evm_fee_in_cent; - #[test] fn fee_growth_simulator_starting_with_genesis_chain() { TestNet::reset(); @@ -216,6 +220,39 @@ fn substrate_and_evm_fee_growth_simulator_with_idle_chain() { } }); } +pub fn get_evm_fee_in_cent(nonce: u128) -> f64 { + let treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); + + let omni_sell = hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { + asset_in: HDX, + asset_out: DAI, + amount: UNITS, + 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( + evm_signed_origin(evm_address()), + evm_address(), + DISPATCH_ADDR, + omni_sell.encode(), + U256::from(0), + gas_limit, + gas_price.0 * 10, + None, + Some(U256::from(nonce)), + [].into(), + )); + + let new_treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); + let fee_weth_evm = new_treasury_eth_balance - treasury_eth_balance; + + let fee_in_cents = ETH_USD_SPOT_PRICE * fee_weth_evm as f64 / 1000000000000000000.0; + round(fee_in_cents) +} fn round(fee_in_cent: f64) -> f64 { let decimal_places = 6; From 3bbf22bf614fff34bddcc7c996dd98cdfdd1d9dd Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 6 Feb 2024 16:08:03 +0100 Subject: [PATCH 22/64] add benchmarking for dynamic evm fee pallet --- Cargo.lock | 1 + pallets/dynamic-evm-fee/Cargo.toml | 13 +- pallets/dynamic-evm-fee/src/lib.rs | 11 +- pallets/dynamic-evm-fee/src/tests/mock.rs | 2 +- pallets/dynamic-evm-fee/src/weights.rs | 107 +++++++++ .../src/benchmarking/dynamic_evm_fee.rs | 225 ++++++++++++++++++ runtime/hydradx/src/benchmarking/mod.rs | 12 +- runtime/hydradx/src/benchmarking/omnipool.rs | 2 +- runtime/hydradx/src/evm/mod.rs | 1 + runtime/hydradx/src/lib.rs | 2 + .../hydradx/src/weights/dynamic_evm_fee.rs | 74 ++++++ runtime/hydradx/src/weights/mod.rs | 1 + 12 files changed, 444 insertions(+), 7 deletions(-) create mode 100644 pallets/dynamic-evm-fee/src/weights.rs create mode 100644 runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs create mode 100644 runtime/hydradx/src/weights/dynamic_evm_fee.rs diff --git a/Cargo.lock b/Cargo.lock index 46b200388..e124233d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7467,6 +7467,7 @@ dependencies = [ name = "pallet-dynamic-evm-fee" version = "1.0.0" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "hydra-dx-math", diff --git a/pallets/dynamic-evm-fee/Cargo.toml b/pallets/dynamic-evm-fee/Cargo.toml index 117f74e7a..4a778781f 100644 --- a/pallets/dynamic-evm-fee/Cargo.toml +++ b/pallets/dynamic-evm-fee/Cargo.toml @@ -27,20 +27,24 @@ hydra-dx-math = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } sp-api = { workspace = true } -sp-core = { workspace = true } sp-std = { workspace = true } sp-runtime = { workspace = true } -sp-io = { workspace = true } +sp-core = { workspace = true} # Evm dependencies pallet-evm = { workspace = true } +# Optional imports for benchmarking +frame-benchmarking = { workspace = true, optional = true } +sp-io = { workspace = true, optional = true } + [dev-dependencies] pallet-currencies = { workspace = true } orml-tokens = { workspace = true, features=["std"] } pallet-balances = { workspace = true, features=["std"] } test-utils = { workspace = true } pallet-transaction-payment = { workspace = true } +frame-benchmarking = { workspace = true } [features] default = ["std"] @@ -57,5 +61,10 @@ std = [ "orml-traits/std", "hydradx-traits/std", "primitives/std", + "frame-benchmarking/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "sp-io", ] try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index fbc4cba56..4eba10913 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -21,9 +21,11 @@ mod tests; pub mod types; +pub mod weights; // Re-export pallet items so that they can be accessed from the crate namespace. pub use pallet::*; +pub use weights::WeightInfo; use crate::types::MultiplierProvider; use codec::HasCompact; @@ -68,6 +70,9 @@ pub mod pallet { /// Eth Asset Id #[pallet::constant] type WethAssetId: Get; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; } /// The current storage version. @@ -135,7 +140,9 @@ pub mod pallet { *old_base_fee_per_gas = U256::from(new_base_fee_per_gas); }); - Weight::default() //TODO: benchmark + let mut weight = Weight::default(); + weight.saturating_accrue(T::WeightInfo::on_initialize()); + weight } } } @@ -143,6 +150,6 @@ impl pallet_evm::FeeCalculator for Pallet { fn min_gas_price() -> (U256, Weight) { // Return some meaningful gas price and weight let base_fee_per_gas = Self::base_evm_fee(); - (base_fee_per_gas.into(), Weight::from_parts(7u64, 0)) //TODO: add the weight once benchmarked + (base_fee_per_gas.into(), T::WeightInfo::on_initialize()) //TODO: add the weight once benchmarked } } diff --git a/pallets/dynamic-evm-fee/src/tests/mock.rs b/pallets/dynamic-evm-fee/src/tests/mock.rs index e8a32e828..0e6dc4d27 100644 --- a/pallets/dynamic-evm-fee/src/tests/mock.rs +++ b/pallets/dynamic-evm-fee/src/tests/mock.rs @@ -150,8 +150,8 @@ impl Config for Test { type DefaultBaseFeePerGas = DefaultBaseDFeePerGas; type Multiplier = MultiplierProviderMock; type NativePriceOracle = NativePriceOracleMock; - type WethAssetId = HdxAssetId; + type WeightInfo = (); } pub struct DefaultRouteProvider; diff --git a/pallets/dynamic-evm-fee/src/weights.rs b/pallets/dynamic-evm-fee/src/weights.rs new file mode 100644 index 000000000..838a95c3f --- /dev/null +++ b/pallets/dynamic-evm-fee/src/weights.rs @@ -0,0 +1,107 @@ +// This file is part of HydraDX. + +// Copyright (C) 2020-2023 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +//! Autogenerated weights for `pallet_dynamic_evm_fee` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-02-06, STEPS: `10`, REPEAT: `30`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `dmoka-msi-pc`, CPU: `AMD Ryzen 9 5900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` + +// Executed Command: +// target/release/hydradx +// benchmark +// pallet +// --chain=dev +// --steps=10 +// --repeat=30 +// --wasm-execution=compiled +// --heap-pages=4096 +// --template=.maintain/pallet-weight-template.hbs +// --pallet=pallet-dynamic-evm-fee +// --output=dynamic-evm-fee2.rs +// --extrinsic=* + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `pallet_dynamic_evm_fee`. +pub trait WeightInfo { + fn on_initialize() -> Weight; +} + +/// Weights for `pallet_dynamic_evm_fee` using the HydraDX node and recommended hardware. +pub struct HydraWeight(PhantomData); +impl WeightInfo for HydraWeight { + /// Storage: `DynamicEvmFee::BaseFeePerGas` (r:1 w:1) + /// Proof: `DynamicEvmFee::BaseFeePerGas` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::NextAssetId` (r:1 w:0) + /// Proof: `AssetRegistry::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::LocationAssets` (r:1 w:0) + /// Proof: `AssetRegistry::LocationAssets` (`max_values`: None, `max_size`: Some(622), added: 3097, mode: `MaxEncodedLen`) + /// Storage: `MultiTransactionPayment::AcceptedCurrencies` (r:1 w:0) + /// Proof: `MultiTransactionPayment::AcceptedCurrencies` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Router::Routes` (r:1 w:0) + /// Proof: `Router::Routes` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `EmaOracle::Oracles` (r:4 w:0) + /// Proof: `EmaOracle::Oracles` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + fn on_initialize() -> Weight { + // Proof Size summary in bytes: + // Measured: `2709` + // Estimated: `11598` + // Minimum execution time: 64_849_000 picoseconds. + Weight::from_parts(66_099_000, 11598) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `DynamicEvmFee::BaseFeePerGas` (r:1 w:1) + /// Proof: `DynamicEvmFee::BaseFeePerGas` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::NextAssetId` (r:1 w:0) + /// Proof: `AssetRegistry::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::LocationAssets` (r:1 w:0) + /// Proof: `AssetRegistry::LocationAssets` (`max_values`: None, `max_size`: Some(622), added: 3097, mode: `MaxEncodedLen`) + /// Storage: `MultiTransactionPayment::AcceptedCurrencies` (r:1 w:0) + /// Proof: `MultiTransactionPayment::AcceptedCurrencies` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Router::Routes` (r:1 w:0) + /// Proof: `Router::Routes` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `EmaOracle::Oracles` (r:4 w:0) + /// Proof: `EmaOracle::Oracles` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + fn on_initialize() -> Weight { + // Proof Size summary in bytes: + // Measured: `2709` + // Estimated: `11598` + // Minimum execution time: 64_849_000 picoseconds. + Weight::from_parts(66_099_000, 11598) + .saturating_add(RocksDbWeight::get().reads(10_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs b/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs new file mode 100644 index 000000000..2d4bd3486 --- /dev/null +++ b/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs @@ -0,0 +1,225 @@ +// This file is part of Basilisk-node + +// Copyright (C) 2020-2021 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate::{AccountId, AssetId, Balance, Currencies, EmaOracle, Runtime, System}; +use frame_benchmarking::account; +use frame_benchmarking::BenchmarkError; +use frame_support::assert_ok; +use frame_support::traits::{OnFinalize, OnInitialize}; +use frame_system::RawOrigin; +use hydradx_traits::router::PoolType; +use hydradx_traits::router::RouteProvider; +use hydradx_traits::PriceOracle; +use orml_benchmarking::runtime_benchmarks; +use orml_traits::MultiCurrencyExtended; +use pallet_route_executor::MAX_NUMBER_OF_TRADES; +use primitives::{BlockNumber, Price}; +use sp_runtime::traits::SaturatedConversion; +use sp_runtime::{DispatchResult, FixedU128}; + +type MultiPaymentPallet = pallet_transaction_multi_payment::Pallet; +type DynamicEvmFeePallet = pallet_dynamic_evm_fee::Pallet; +type XykPallet = pallet_xyk::Pallet; +type Router = pallet_route_executor::Pallet; +use crate::evm::WETH_ASSET_LOCATION; +use hydradx_traits::router::AssetPair; +use hydradx_traits::router::Trade; +use hydradx_traits::OraclePeriod; +use pallet_dynamic_evm_fee::BaseFeePerGas; + +const SEED: u32 = 1; + +const UNITS: Balance = 1_000_000_000_000; + +pub fn update_balance(currency_id: AssetId, who: &AccountId, balance: Balance) { + assert_ok!(>::update_balance( + currency_id, + who, + balance.saturated_into() + )); +} + +runtime_benchmarks! { + { Runtime, pallet_dynamic_evm_fee} + + + on_initialize{ + //let maker: AccountId = account("maker", 0, SEED); + + crate::benchmarking::omnipool::init()?; + + let acc = Omnipool::protocol_account(); + // Register new asset in asset registry + let token_id = register_asset(b"AS1".to_vec(), 1u128).map_err(|_| BenchmarkError::Stop("Failed to register asset"))?; + assert_eq!(token_id, 1000001, "Token ID should be 1000001"); + set_location(token_id, WETH_ASSET_LOCATION).map_err(|_| BenchmarkError::Stop("Failed to set location for weth"))?; + add_as_accepted_currency(token_id, FixedU128::from_inner(16420844565569051996)).map_err(|_| BenchmarkError::Stop("Failed to add token as accepted currency"))?; + // Create account for token provider and set balance + let owner: AccountId = account("owner", 0, 1); + + let token_price = FixedU128::from((1,5)); + let token_amount = 200_000_000_000_000_u128; + + update_balance(token_id, &acc, token_amount); + update_balance(0, &owner, 1_000_000_000_000_000_u128); + + // Add the token to the pool + Omnipool::add_token(RawOrigin::Root.into(), token_id, token_price, Permill::from_percent(100), owner.clone())?; + let seller: AccountId = account("seller", 3, 1); + update_balance(0, &seller, 500_000_000_000_000_u128); + Omnipool::sell(RawOrigin::Signed(seller.clone()).into(), 0, token_id, 10000000000000, 0)?; + + set_period(10); + let base_fee_per_gas = >::get(); + + }: { + DynamicEvmFeePallet::::on_initialize(1u32.into()) + } + verify{ + assert!(>::get() != base_fee_per_gas); + } +} +use crate::Omnipool; +use sp_runtime::Permill; +/* +use crate::Omnipool; +use sp_runtime::Permill; +const HDX: AssetId = 0; +const DAI: AssetId = 2; + +pub fn init() -> DispatchResult { + let stable_amount: Balance = 1_000_000_000_000_000u128; + let native_amount: Balance = 1_000_000_000_000_000u128; + let stable_price: FixedU128 = FixedU128::from((1, 2)); + let native_price: FixedU128 = FixedU128::from(1); + + let acc = Omnipool::protocol_account(); + + update_balance(DAI, &acc, stable_amount); + update_balance(HDX, &acc, native_amount); + + Omnipool::add_token( + RawOrigin::Root.into(), + HDX, + native_price, + Permill::from_percent(100), + acc.clone(), + )?; + Omnipool::add_token( + RawOrigin::Root.into(), + DAI, + stable_price, + Permill::from_percent(100), + acc, + )?; + + Ok(()) +}*/ + +fn create_xyk_pool(asset_a: AssetId, amount_a: Balance, asset_b: AssetId, amount_b: Balance) +where + ::RuntimeOrigin: core::convert::From>, +{ + let maker: AccountId = account("xyk-maker", 0, SEED); + + assert_ok!(Currencies::update_balance( + RawOrigin::Root.into(), + maker.clone(), + asset_a, + amount_a as i128, + )); + assert_ok!(Currencies::update_balance( + RawOrigin::Root.into(), + maker.clone(), + asset_b, + amount_b as i128, + )); + + assert_ok!(XykPallet::::create_pool( + RawOrigin::Signed(maker).into(), + asset_a, + amount_a, + asset_b, + amount_b, + )); +} + +fn xyk_sell(asset_a: AssetId, asset_b: AssetId, amount_a: Balance) +where + ::RuntimeOrigin: core::convert::From>, +{ + let maker: AccountId = account("xyk-seller", 0, SEED); + + assert_ok!(Currencies::update_balance( + RawOrigin::Root.into(), + maker.clone(), + asset_a, + amount_a as i128, + )); + assert_ok!(XykPallet::::sell( + RawOrigin::Signed(maker).into(), + asset_a, + asset_b, + amount_a, + u128::MIN, + false + )); +} + +fn set_period(to: u32) { + while System::block_number() < Into::::into(to) { + let b = System::block_number(); + + System::on_finalize(b); + EmaOracle::on_finalize(b); + + System::on_initialize(b + 1_u32); + EmaOracle::on_initialize(b + 1_u32); + + System::set_block_number(b + 1_u32); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::NativeExistentialDeposit; + use orml_benchmarking::impl_benchmark_test_suite; + use sp_runtime::BuildStorage; + + fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_asset_registry::GenesisConfig:: { + registered_assets: vec![ + (b"LRNA".to_vec(), 1_000u128, Some(1)), + (b"DAI".to_vec(), 1_000u128, Some(2)), + ], + native_asset_name: b"HDX".to_vec(), + native_existential_deposit: NativeExistentialDeposit::get(), + } + .assimilate_storage(&mut t) + .unwrap(); + + sp_io::TestExternalities::new(t) + } + + impl_benchmark_test_suite!(new_test_ext(),); +} diff --git a/runtime/hydradx/src/benchmarking/mod.rs b/runtime/hydradx/src/benchmarking/mod.rs index bf8347fae..c177242fd 100644 --- a/runtime/hydradx/src/benchmarking/mod.rs +++ b/runtime/hydradx/src/benchmarking/mod.rs @@ -3,15 +3,17 @@ pub mod currencies; pub mod dca; pub mod duster; +pub mod dynamic_evm_fee; pub mod multi_payment; pub mod omnipool; pub mod route_executor; pub mod tokens; pub mod vesting; -use crate::AssetRegistry; +use crate::{AssetLocation, AssetRegistry, MultiTransactionPayment}; use frame_system::RawOrigin; +use pallet_transaction_multi_payment::Price; use primitives::{AssetId, Balance}; use sp_std::vec; use sp_std::vec::Vec; @@ -29,6 +31,14 @@ pub fn register_asset(name: Vec, deposit: Balance) -> Result { .map_err(|_| ()) } +pub fn set_location(asset_id: AssetId, location: AssetLocation) -> Result<(), ()> { + AssetRegistry::set_location(RawOrigin::Root.into(), asset_id, location).map_err(|_| ()) +} + +pub fn add_as_accepted_currency(asset_id: AssetId, price: Price) -> Result<(), ()> { + MultiTransactionPayment::add_currency(RawOrigin::Root.into(), asset_id, price).map_err(|_| ()) +} + #[allow(dead_code)] pub fn update_asset(asset_id: AssetId, name: Vec, deposit: Balance) -> Result<(), ()> { AssetRegistry::update( diff --git a/runtime/hydradx/src/benchmarking/omnipool.rs b/runtime/hydradx/src/benchmarking/omnipool.rs index 2e88edab0..8e259d2a3 100644 --- a/runtime/hydradx/src/benchmarking/omnipool.rs +++ b/runtime/hydradx/src/benchmarking/omnipool.rs @@ -51,7 +51,7 @@ fn run_to_block(to: u32) { const HDX: AssetId = 0; const DAI: AssetId = 2; -fn init() -> DispatchResult { +pub fn init() -> DispatchResult { let stable_amount: Balance = 1_000_000_000_000_000u128; let native_amount: Balance = 1_000_000_000_000_000u128; let stable_price: FixedU128 = FixedU128::from((1, 2)); diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index 347c7093e..46c951d90 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -194,4 +194,5 @@ impl pallet_dynamic_evm_fee::Config for crate::Runtime { DCAOraclePeriod, >; type WethAssetId = WethAssetId; + type WeightInfo = crate::weights::dynamic_evm_fee::HydraWeight; } diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 3a1a8dbe7..fbf99247d 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -638,6 +638,7 @@ impl_runtime_apis! { orml_list_benchmark!(list, extra, pallet_omnipool, benchmarking::omnipool); orml_list_benchmark!(list, extra, pallet_route_executor, benchmarking::route_executor); orml_list_benchmark!(list, extra, pallet_dca, benchmarking::dca); + orml_list_benchmark!(list, extra, pallet_dynamic_evm_fee, benchmarking::dynamic_evm_fee); let storage_info = AllPalletsWithSystem::storage_info(); @@ -719,6 +720,7 @@ impl_runtime_apis! { orml_add_benchmark!(params, batches, pallet_omnipool, benchmarking::omnipool); orml_add_benchmark!(params, batches, pallet_route_executor, benchmarking::route_executor); orml_add_benchmark!(params, batches, pallet_dca, benchmarking::dca); + orml_add_benchmark!(params, batches, pallet_dynamic_evm_fee, benchmarking::dynamic_evm_fee); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) diff --git a/runtime/hydradx/src/weights/dynamic_evm_fee.rs b/runtime/hydradx/src/weights/dynamic_evm_fee.rs new file mode 100644 index 000000000..776101ca3 --- /dev/null +++ b/runtime/hydradx/src/weights/dynamic_evm_fee.rs @@ -0,0 +1,74 @@ +// This file is part of HydraDX. + +// Copyright (C) 2020-2023 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_dynamic_evm_fee` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-02-06, STEPS: `10`, REPEAT: `30`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `dmoka-msi-pc`, CPU: `AMD Ryzen 9 5900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 + +// Executed Command: +// target/release/hydradx +// benchmark +// pallet +// --chain=dev +// --steps=10 +// --repeat=30 +// --wasm-execution=compiled +// --heap-pages=4096 +// --template=.maintain/pallet-weight-template-no-back.hbs +// --pallet=pallet-dynamic-evm-fee +// --output=dynamic-evm-fee.rs +// --extrinsic=* + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_dynamic_evm_fee`. +pub struct HydraWeight(PhantomData); +impl pallet_dynamic_evm_fee::WeightInfo for HydraWeight { + /// Storage: `DynamicEvmFee::BaseFeePerGas` (r:1 w:1) + /// Proof: `DynamicEvmFee::BaseFeePerGas` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::NextAssetId` (r:1 w:0) + /// Proof: `AssetRegistry::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::LocationAssets` (r:1 w:0) + /// Proof: `AssetRegistry::LocationAssets` (`max_values`: None, `max_size`: Some(622), added: 3097, mode: `MaxEncodedLen`) + /// Storage: `MultiTransactionPayment::AcceptedCurrencies` (r:1 w:0) + /// Proof: `MultiTransactionPayment::AcceptedCurrencies` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Router::Routes` (r:1 w:0) + /// Proof: `Router::Routes` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `EmaOracle::Oracles` (r:4 w:0) + /// Proof: `EmaOracle::Oracles` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + fn on_initialize() -> Weight { + // Proof Size summary in bytes: + // Measured: `2709` + // Estimated: `11598` + // Minimum execution time: 68_199_000 picoseconds. + Weight::from_parts(71_750_000, 11598) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} \ No newline at end of file diff --git a/runtime/hydradx/src/weights/mod.rs b/runtime/hydradx/src/weights/mod.rs index 1cd454e94..0f701c385 100644 --- a/runtime/hydradx/src/weights/mod.rs +++ b/runtime/hydradx/src/weights/mod.rs @@ -8,6 +8,7 @@ pub mod currencies; pub mod dca; pub mod democracy; pub mod duster; +pub mod dynamic_evm_fee; pub mod ema_oracle; pub mod identity; pub mod lbp; From 0524d92e32258240d315b5883e1d32be72660ee3 Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 6 Feb 2024 16:09:22 +0100 Subject: [PATCH 23/64] removed done todo comment --- pallets/dynamic-evm-fee/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 4eba10913..fcd83e1fc 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -150,6 +150,6 @@ impl pallet_evm::FeeCalculator for Pallet { fn min_gas_price() -> (U256, Weight) { // Return some meaningful gas price and weight let base_fee_per_gas = Self::base_evm_fee(); - (base_fee_per_gas.into(), T::WeightInfo::on_initialize()) //TODO: add the weight once benchmarked + (base_fee_per_gas.into(), T::WeightInfo::on_initialize()) } } From 1373db743d5bf33192e9f4b6520472ac67e41efb Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 6 Feb 2024 16:30:27 +0100 Subject: [PATCH 24/64] remove not needed comment --- primitives/src/constants.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/src/constants.rs b/primitives/src/constants.rs index 34be3975f..8f7c1b083 100644 --- a/primitives/src/constants.rs +++ b/primitives/src/constants.rs @@ -20,7 +20,7 @@ pub mod currency { pub const FORTUNE: Balance = u128::MAX; pub const UNITS: Balance = 1_000_000_000_000; - pub const DOLLARS: Balance = UNITS * 100; // 100 UNITS ~= 1 $, and we divide by three as HDX price is high (~0.02$), but we want to reduce the fee price + pub const DOLLARS: Balance = UNITS * 100; // 100 UNITS ~= 1 $ pub const CENTS: Balance = DOLLARS / 100; // 1 UNITS ~= 1 cent pub const MILLICENTS: Balance = CENTS / 1_000; pub const NATIVE_EXISTENTIAL_DEPOSIT: Balance = CENTS; From 9e07d0353502133aa02898e47f4aee8be065c26a Mon Sep 17 00:00:00 2001 From: dmoka Date: Tue, 6 Feb 2024 17:20:13 +0100 Subject: [PATCH 25/64] fix dca tests as fee were too low and had BelowMinimum issue wrt ed --- runtime/hydradx/src/benchmarking/dca.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/runtime/hydradx/src/benchmarking/dca.rs b/runtime/hydradx/src/benchmarking/dca.rs index 4d0c571b1..f0aec450c 100644 --- a/runtime/hydradx/src/benchmarking/dca.rs +++ b/runtime/hydradx/src/benchmarking/dca.rs @@ -41,8 +41,8 @@ use pallet_route_executor::Trade; use pallet_route_executor::MAX_NUMBER_OF_TRADES; use scale_info::prelude::vec::Vec; use sp_runtime::traits::ConstU32; -use sp_runtime::FixedU128; use sp_runtime::{DispatchError, Permill}; +use sp_runtime::{DispatchResult, FixedU128}; use sp_std::vec; pub const HDX: AssetId = 0; @@ -172,6 +172,13 @@ fn create_account_with_native_balance() -> Result { Ok(caller) } +fn fund_treasury() -> DispatchResult { + let treasury = ::FeeReceiver::get(); + >::update_balance(HDX, &treasury, 500_000_000_000_000i128)?; + + Ok(()) +} + runtime_benchmarks! { {Runtime, pallet_dca} @@ -184,9 +191,11 @@ runtime_benchmarks! { let amount_buy = 200 * ONE; >::update_balance(HDX, &seller, 500_000_000_000_000i128)?; - >::update_balance(HDX, &other_seller, 20_000_000_000_000_000_000_000i128)?; + //Fund treasury with some HDX to prevent BelowMinimum issue due to low fee + fund_treasury()?; + let schedule1 = schedule_buy_fake(seller.clone(), HDX, DAI, amount_buy); let execution_block = 1001u32; @@ -225,9 +234,10 @@ runtime_benchmarks! { let amount_sell = 100 * ONE; >::update_balance(HDX, &seller, 20_000_000_000_000_000i128)?; - >::update_balance(HDX, &other_seller, 20_000_000_000_000_000_000_000i128)?; + fund_treasury()?; //Fund treasury with some HDX to prevent BelowMinimum issue due to low fee + fund_treasury()?; //Fund treasury with some HDX to prevent BelowMinimum issue due to low fee let schedule1 = schedule_sell_fake(seller.clone(), HDX, DAI, amount_sell); let execution_block = 1001u32; @@ -259,6 +269,7 @@ runtime_benchmarks! { on_initialize_with_empty_block{ let seller: AccountId = account("seller", 3, 1); + fund_treasury()?; //Fund treasury with some HDX to prevent BelowMinimum issue due to low fee let execution_block = 100u32; assert_eq!(DCA::schedules::(execution_block), None); @@ -274,6 +285,7 @@ runtime_benchmarks! { schedule{ let caller: AccountId = create_account_with_native_balance()?; + fund_treasury()?; //Fund treasury with some HDX to prevent BelowMinimum issue due to low fee let asset_1 = register_asset(b"AS1".to_vec(), 1u128).map_err(|_| BenchmarkError::Stop("Failed to register asset"))?; let asset_2 = register_asset(b"AS2".to_vec(), 1u128).map_err(|_| BenchmarkError::Stop("Failed to register asset"))?; @@ -373,6 +385,7 @@ runtime_benchmarks! { terminate { let caller: AccountId = create_account_with_native_balance()?; + fund_treasury()?; //Fund treasury with some HDX to prevent BelowMinimum issue due to low fee >::update_balance(HDX, &caller, 100_000_000_000_000_000i128)?; From eaba42d4e2ab8a1e151ae245cc2cb449332f2601 Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 7 Feb 2024 08:24:38 +0100 Subject: [PATCH 26/64] cleaning up --- integration-tests/src/evm.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index 55fdcf959..cb76f544a 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -682,11 +682,6 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { let new_treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); let fee_weth_evm = new_treasury_eth_balance - treasury_eth_balance; - /* - assert_eq!(fee_weth_native, 4282317006577); - assert_eq!(fee_weth_evm, 4716541412000); - println!("FEE in WETH: {:?}", fee_weth_evm); - println!("FEE in hdx: {:?}", fee_weth_native);*/ let fee_difference = fee_weth_evm - fee_weth_native; @@ -756,7 +751,6 @@ pub fn init_omnipol() { pub const DISPATCH_ADDR: H160 = addr(1025); -//TODO: Here we should use the PROD one, as used specifily in test call pub fn gas_price() -> U256 { U256::from(hydradx_runtime::evm::DEFAULT_BASE_FEE_PER_GAS) //We divide by three as we const `FEE_DIVIDER` set to 3 in system.rs. } From 16c2db30aaeffc6dffcb4bc932d61045c3a885d5 Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 7 Feb 2024 09:44:19 +0100 Subject: [PATCH 27/64] fix warning message --- pallets/dynamic-evm-fee/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index fcd83e1fc..d3bda1efd 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -106,7 +106,7 @@ pub mod pallet { .saturating_mul(3); let Some(eth_hdx_price) = T::NativePriceOracle::price(T::WethAssetId::get()) else { - log::warn!(target: "runtime::dynamic-evm-fee", "Can not get ETH-HDX price from oracle"); + log::warn!(target: "runtime::dynamic-evm-fee", "Could not get ETH-HDX price from oracle"); return; }; let eth_hdx_price = FixedU128::from_rational(eth_hdx_price.n, eth_hdx_price.d); @@ -120,7 +120,7 @@ pub mod pallet { let Some(percentage_change) = price_diff .saturating_mul(FixedU128::saturating_from_integer(100)) .const_checked_div(ETH_HDX_REFERENCE_PRICE) else { - log::warn!(target: "runtime::dynamic-evm-fee", "Unexpected error: Can not calculate percentage change"); + log::warn!(target: "runtime::dynamic-evm-fee", "Unexpected error: Could not calculate percentage change"); return; }; From 941cf0f5d6543de551652811d6463ff424be5f3b Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 7 Feb 2024 12:49:46 +0100 Subject: [PATCH 28/64] add missing test --- .../src/tests/on_initialize.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs index 9691e4942..f117b411e 100644 --- a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs +++ b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs @@ -42,6 +42,29 @@ fn should_decrease_evm_fee_when_hdx_pumping_10percent_against_eth() { }); } +#[test] +fn should_not_change_when_price_pumps_then_remains_same_in_consquent_block() { + ExtBuilder::default().build().execute_with(|| { + //Arrange + set_oracle_price(Ratio::new( + DEFAULT_ETH_HDX_ORACLE_PRICE.n * 90 / 100, + DEFAULT_ETH_HDX_ORACLE_PRICE.d, + )); + + DynamicEvmFee::on_initialize(1); + + let new_base_fee = DynamicEvmFee::base_evm_fee(); + assert_eq!(new_base_fee, U256::from(24071998)); + + //Act + DynamicEvmFee::on_initialize(2); + + //Assert + let new_base_fee = DynamicEvmFee::base_evm_fee(); + assert_eq!(new_base_fee, U256::from(24071998)); + }); +} + #[test] fn should_decrease_evm_fee_when_hdx_pumping_1percent_against_eth() { ExtBuilder::default().build().execute_with(|| { From f3fb177ff1eeb3e5dcb666a695f71bb2b2c1192a Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 7 Feb 2024 12:50:36 +0100 Subject: [PATCH 29/64] added scripts for evm hack --- scripts/init-testnet/evm/assets.json | 254 ++++++++++++++++++++++ scripts/init-testnet/evm/dispatch.ts | 67 ++++++ scripts/init-testnet/evm/init_chain.ts | 287 +++++++++++++++++++++++++ scripts/init-testnet/package-lock.json | 92 +++++++- scripts/init-testnet/package.json | 3 +- 5 files changed, 701 insertions(+), 2 deletions(-) create mode 100644 scripts/init-testnet/evm/assets.json create mode 100644 scripts/init-testnet/evm/dispatch.ts create mode 100644 scripts/init-testnet/evm/init_chain.ts diff --git a/scripts/init-testnet/evm/assets.json b/scripts/init-testnet/evm/assets.json new file mode 100644 index 000000000..65d53cef6 --- /dev/null +++ b/scripts/init-testnet/evm/assets.json @@ -0,0 +1,254 @@ +{ + "0": { + "asset": { + "name": "HydraDX", + "assetType": "Token", + "existentialDeposit": "1,000,000,000,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "HDX", + "decimals": "12" + } + }, + "1": { + "asset": { + "name": "Lerna", + "assetType": "Token", + "existentialDeposit": "400,000,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "LRNA", + "decimals": "12" + } + }, + "2": { + "asset": { + "name": "DAI Stablecoin (via Wormhole)", + "assetType": "Token", + "existentialDeposit": "10,000,000,000,000,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "DAI", + "decimals": "18" + } + }, + "3": { + "asset": { + "name": "Wrapped Bitcoin (via Wormhole)", + "assetType": "Token", + "existentialDeposit": "44", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "WBTC", + "decimals": "8" + } + }, + "4": { + "asset": { + "name": "Ethereum (via Wormhole)", + "assetType": "Token", + "existentialDeposit": "7,000,000,000,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "WEX", + "decimals": "18" + } + }, + "5": { + "asset": { + "name": "Polkadot", + "assetType": "Token", + "existentialDeposit": "17,540,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "DOT", + "decimals": "10" + } + }, + "6": { + "asset": { + "name": "ApeCoin (via Wormhole)", + "assetType": "Token", + "existentialDeposit": "2,518,891,687,657,430", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "APE", + "decimals": "18" + } + }, + "7": { + "asset": { + "name": "USD Coin (via Wormhole)", + "assetType": "Token", + "existentialDeposit": "10,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "USDC", + "decimals": "6" + } + }, + "8": { + "asset": { + "name": "Phala", + "assetType": "Token", + "existentialDeposit": "54,945,054,945", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "PHA", + "decimals": "12" + } + }, + "9": { + "asset": { + "name": "Astar", + "assetType": "Token", + "existentialDeposit": "147,058,823,529,412,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "ASTR", + "decimals": "18" + } + }, + "10": { + "asset": { + "name": "Statemint USDT", + "assetType": "Token", + "existentialDeposit": "10,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "USDT", + "decimals": "6" + } + }, + "11": { + "asset": { + "name": "interBTC", + "assetType": "Token", + "existentialDeposit": "36", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "iBTC", + "decimals": "8" + } + }, + "12": { + "asset": { + "name": "Zeitgeist", + "assetType": "Token", + "existentialDeposit": "1,204,151,916", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "ZTG", + "decimals": "10" + } + }, + "13": { + "asset": { + "name": "Centrifuge", + "assetType": "Token", + "existentialDeposit": "32,467,532,467,532,500", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "CFG", + "decimals": "18" + } + }, + "14": { + "asset": { + "name": "Bifrost Native Coin", + "assetType": "Token", + "existentialDeposit": "68,795,189,840", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "BNC", + "decimals": "12" + } + }, + "15": { + "asset": { + "name": "Bifrost Voucher DOT", + "assetType": "Token", + "existentialDeposit": "18,761,726", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "vDOT", + "decimals": "10" + } + }, + "16": { + "asset": { + "name": "Glimmer", + "assetType": "Token", + "existentialDeposit": "34,854,864,344,868,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "GLMR", + "decimals": "18" + } + }, + "17": { + "asset": { + "name": "Interlay", + "assetType": "Token", + "existentialDeposit": "6,164,274,209", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "INTR", + "decimals": "10" + } + }, + "18": { + "asset": { + "name": "Random token 1 (via Wormhole)", + "assetType": "Token", + "existentialDeposit": "7,000,000,000,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "RAND1", + "decimals": "18" + } + }, + "19": { + "asset": { + "name": "Random token 2 (via Wormhole)", + "assetType": "Token", + "existentialDeposit": "7,000,000,000,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "RAND2", + "decimals": "18" + } + }, + "20": { + "asset": { + "name": "Ethereum (via Moonbeam)", + "assetType": "Token", + "existentialDeposit": "7,000,000,000,000", + "xcmRateLimit": null + }, + "metadata": { + "symbol": "WETH", + "decimals": "18" + } + } + } \ No newline at end of file diff --git a/scripts/init-testnet/evm/dispatch.ts b/scripts/init-testnet/evm/dispatch.ts new file mode 100644 index 000000000..a192bd963 --- /dev/null +++ b/scripts/init-testnet/evm/dispatch.ts @@ -0,0 +1,67 @@ +const { ethers } = require('ethers'); + +async function main() { + // Define the Ethereum RPC URL + //const ethereumRpcUrl = "https://rpc.nice.hydration.cloud"; // Replace with your Ethereum RPC URL + + const ethereumRpcUrl = "http://127.0.0.1:9988"; // Replace with your Ethereum RPC URL + + // Create a provider using the Ethereum RPC URL + const provider = new ethers.JsonRpcProvider(ethereumRpcUrl); + + try { + // Example: Fetch the Ethereum block number + const blockNumber = await provider.getBlockNumber(); + console.log("Ethereum Block Number:", blockNumber); + + // Example: Fetch the balance of an Ethereum address + const address = "0x222222ff7Be76052e023Ec1a306fCca8F9659D80"; // Replace with the Ethereum address you want to check + const balance = await provider.getBalance(address); + console.log("Ethereum Balance (Wei):", balance.toString()); + + + const privateKey = '42d8d953e4f9246093a33e9ca6daa078501012f784adfe4bbed57918ff13be14'; + const wallet = new ethers.Wallet(privateKey, provider); + + const dispatchContractAddress = '0x0000000000000000000000000000000000000401'; + + try { + const extrinsicData = '0x3b05000000000500000000a0724e18090000000000000000000000000000000000000000000000000000'; // Replace with your extrinsic data + const nonce = await provider.getTransactionCount(wallet.address, 'latest'); + + const tx = { + to: dispatchContractAddress, + value: 0, + nonce: nonce, + gasLimit: 100000, // Adjust the gas limit accordingly + gasPrice: ethers.parseUnits('80000000', 'wei'), // Adjust the gas price accordingly + data: extrinsicData, + }; + + const signer = wallet.connect(provider); // Connect the wallet to the provider + const signedTx = await signer.signTransaction(tx); // Sign the transaction + //const txResponse = await provider.sendTransaction(signedTx); // Send the signed transaction + const signer2= wallet.connect(provider); // Connect the wallet to the provider + + await signer2.sendTransaction(tx); + + //await signer.sendTransaction(tx); + /* const signedTx = await wallet.signTransaction(tx); + const txResponse = await provider.send(signedTx);*/ + + // console.log('Transaction Hash:', txResponse.hash); + + // const receipt = await txResponse.wait(); + //console.log('Transaction Receipt:', receipt); + } catch (error) { + console.error('Error:', error); + } + + + + } catch (error) { + console.error("Error:", error); + } +} + +main(); \ No newline at end of file diff --git a/scripts/init-testnet/evm/init_chain.ts b/scripts/init-testnet/evm/init_chain.ts new file mode 100644 index 000000000..753b6dd87 --- /dev/null +++ b/scripts/init-testnet/evm/init_chain.ts @@ -0,0 +1,287 @@ +// Required imports +const { ApiPromise, WsProvider } = require('@polkadot/api'); +const { hexToU8a } = require('@polkadot/util'); +const { encodeAddress, decodeAddress } = require('@polkadot/util-crypto'); +/*const { + isAddress, + getAddress, +} = require('@ethersproject/address') + +*/ +const { Keyring } = require('@polkadot/keyring'); + +/* +export class H160 { + static prefixBytes = Buffer.from("ETH\0") + address: string + + constructor(address: string) { + this.address = safeConvertAddressH160(address) ?? "" + } + + toAccount = () => { + const addressBytes = Buffer.from(this.address.slice(2), "hex") + return encodeAddress( + new Uint8Array( + Buffer.concat([H160.prefixBytes, addressBytes, Buffer.alloc(8)]), + ), + 63, + ) + } + + static fromAccount = (address: string) => { + const decodedBytes = decodeAddress(address) + const addressBytes = decodedBytes.slice(H160.prefixBytes.length, -8) + return ( + safeConvertAddressH160(Buffer.from(addressBytes).toString("hex")) ?? "" + ) + } +} + +export function safeConvertAddressH160(value: string): string | null { + try { + return getAddress(value?.toLowerCase()) + } catch { + return null + } +}*/ + + + +async function main () { + // Initialise the provider to connect to the local node + //const provider = new WsProvider('wss://rpc.nice.hydration.cloud'); + const provider = new WsProvider('ws://127.0.0.1:9988'); + + // Create the API and wait until ready + const api = await ApiPromise.create({ provider }); + + // Retrieve the chain & node information information via rpc calls + const [chain, nodeName, nodeVersion] = await Promise.all([ + api.rpc.system.chain(), + api.rpc.system.name(), + api.rpc.system.version() + ]); + + console.log(`You are connected to chain ${chain} using ${nodeName} v${nodeVersion}`); + + const keyring = new Keyring({ type: 'sr25519' }); + const alice = keyring.addFromUri('//Alice'); + + /*await api.tx.assetRegistry.register( + "test token", + {"Token": 0}, + 1000, + 5, + {symbol: "ttt", decimals: 10}, + null, + null + ).signAndSend(alice, );*/ + + let transactions = []; + + //let evmUser = "7KATdGbFsc58BDyfV9ZtxHEYPt5icvS5itHcJh3yWYmpwG8k"; + //const evmUserAcc = keyring.addFromUri(evmUser); + + /*let balance = await api.query.system.account(alice.publicKey); + console.log(`Alice's HDX balance before tx ${balance.data.free}`); + + let weth = 20; + let wethBalance = await api.query.tokens.accounts(alice.publicKey, weth); + console.log(`Alice's HDX balance before tx ${wethBalance.free}`); + + const nonce = await api.rpc.system.accountNextIndex(alice.publicKey); + await api.tx.evm.withdraw(safeConvertAddressH160(alice.publicKey), "2000000000000").signAndSend(alice, { nonce }); + console.log("Evm tx done"); + + + balance = await api.query.system.account(alice.publicKey); + console.log(`Alice's HDX balance is after evm ${balance.data.free}`);*/ + + assetRegistry(api, transactions); + mintForAlice(api, transactions); + initOmnipool(api, transactions) + setWethLocation(api,transactions); + mintMetamaskWeth(api,transactions); + let tx = api.tx.multiTransactionPayment.addCurrency(20, '16420844565569051996'); + transactions.push(tx); + + let batch = api.tx.utility.batchAll(transactions); + + await api.tx.preimage.notePreimage(batch.method.toHex()).signAndSend(alice); +} + +main().catch(console.error).finally(() => process.exit()); + +function mintForTreasuryDca(api, txs) { + let treasury = "7KQx4f7yU3hqZHfvDVnSfe6mpgAT8Pxyr67LXHV6nsbZo3Tm"; + //weth + txs.push( + api.tx.currencies.updateBalance(treasury, 5, "5000000000000000") + ); + +} + +function mintForAlice(api, txs) { + let alice = "7NPoMQbiA6trJKkjB35uk96MeJD4PGWkLQLH7k7hXEkZpiba"; + txs.push( + api.tx.currencies.updateBalance(alice, 0, "5000000000000000000") + ); + + txs.push(api.tx.currencies.updateBalance(alice, 1, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 2, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 3, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 4, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 5, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 6, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 7, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 8, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 9, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 10, "5000000000000000000")); + txs.push(api.tx.currencies.updateBalance(alice, 20, "5000000000000000000")); + +} + +function assetRegistry(api, txs) { + const assets = require('./assets.json'); + let keys = Object.keys(assets); + + for (let i = 0, l = keys.length; i < l; i++) { + let k = keys[i]; + let a = assets[k]; + let tx; + + if (k == "0") { + tx = api.tx.assetRegistry.setMetadata(k, a.metadata.symbol, a.metadata.decimals); + txs.push(tx); + + continue; + } + + if (k == "1" || k == "2") { + let aType = {}; + aType[a.asset.assetType] = 0; + + tx = api.tx.assetRegistry.update(k, a.asset.name, aType, 100, null); + txs.push(tx); + + tx = api.tx.assetRegistry.setMetadata(k, a.metadata.symbol, a.metadata.decimals); + txs.push(tx); + continue; + } + + let aType = {}; + aType[a.asset.assetType] = 0; + + a.metadata.decimals = Number(a.metadata.decimals); + + tx = api.tx.assetRegistry.register(a.asset.name, aType, 100, k, a.metadata, null, null); + txs.push(tx); + }; + + return txs; +} + +function setWethLocation(api, txs) { + const multiLocation = { + parents: 1, + interior: { + X3: [ + {Parachain: 2004}, + {PalletInstance: 110}, + {AccountKey20: {key: "0xab3f0245b83feb11d15aaffefd7ad465a59817ed"}} + ] + } + }; + + let tx = api.tx.assetRegistry.setLocation(20, multiLocation); + txs.push(tx); + + return txs; +} + + +function mintMetamaskWeth(api, txs) { + let my_original_metamask = "7KATdGbFsc58BDyfV9ZtxHEYPt5icvS5itHcJh3yWYmpwG8k"; + let new_metamask = "7KATdGauM2GcuFoZ91PPA8gp1BxWVLBEor7h8TJT3xDm2f5Y"; + let test_acc = "7KATdGakyhfBGnAt3XVgXTL7cYjzRXeSZHezKNtENcbwWibb" + //hdx + /*txs.push( + api.tx.currencies.updateBalance(new_metamask, 0, "226329588000000000") + );*/ + + //weth + txs.push( + api.tx.currencies.updateBalance(my_original_metamask, 20, "1936329588000000000") + ); + txs.push( + api.tx.currencies.updateBalance(new_metamask, 20, "1936329588000000000") + ); + + txs.push( + api.tx.currencies.updateBalance(test_acc, 20, "1936329588000000000") + ); + + txs.push( + api.tx.currencies.updateBalance(my_original_metamask, 5, "1936329588000000000") + ); + txs.push( + api.tx.currencies.updateBalance(new_metamask, 5, "1936329588000000000") + ); + + txs.push( + api.tx.currencies.updateBalance(test_acc, 5, "1936329588000000000") + ); +} + +/* +function mintStaking(api, txs) { + let stakingPot = "7L53bUTCbRAv4KC8NGQC17Cv8VDWYgbeCnLkT3tShzisck4C"; + //hdx + txs.push( + api.tx.currencies.updateBalance(stakingPot, 0, "1000000000000000") + ); +} + +function initStaking(api, txs) { + txs.push( + api.tx.staking.initializeStaking() + ); +}*/ + + +function initOmnipool(api, txs) { + let omniAccount = "7L53bUTBbfuj14UpdCNPwmgzzHSsrsTWBHX5pys32mVWM3C1"; + //hdx + txs.push( + api.tx.currencies.updateBalance(omniAccount, 0, "936329588000000000") + ); + + //dai + txs.push( + api.tx.currencies.updateBalance(omniAccount, 2, "50000000000000000000000") + ); + + txs.push( + api.tx.currencies.updateBalance(omniAccount, 5, "936329588000000000") + ); + + txs.push( + api.tx.currencies.updateBalance(omniAccount, 20, "1434000000000000000000") + ); + + txs.push( + api.tx.omnipool.addToken(0, "1201500000000000", 1000000, omniAccount) + ); + txs.push( + api.tx.omnipool.addToken(2, "1501500000000000", 1000000, omniAccount) + ); + + txs.push( + api.tx.omnipool.addToken(5, "1701500000000000", 1000000, omniAccount) + ); + + txs.push( + api.tx.omnipool.addToken(20, "16420844565569051996", 1000000, omniAccount) + ); +} \ No newline at end of file diff --git a/scripts/init-testnet/package-lock.json b/scripts/init-testnet/package-lock.json index 017b05f36..2ca8cdc6f 100644 --- a/scripts/init-testnet/package-lock.json +++ b/scripts/init-testnet/package-lock.json @@ -10,9 +10,15 @@ "license": "ISC", "dependencies": { "@polkadot/api": "^9.3.3", - "@polkadot/keyring": "^12.3.2" + "@polkadot/keyring": "^12.3.2", + "ethers": "^6.10.0" } }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", + "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==" + }, "node_modules/@babel/runtime": { "version": "7.22.10", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", @@ -898,6 +904,11 @@ "@types/node": "*" } }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1013,6 +1024,85 @@ "ext": "^1.1.2" } }, + "node_modules/ethers": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.10.0.tgz", + "integrity": "sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.10.0", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers/node_modules/@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==" + }, + "node_modules/ethers/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/ethers/node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", diff --git a/scripts/init-testnet/package.json b/scripts/init-testnet/package.json index 40c90a19d..27c54ae2d 100644 --- a/scripts/init-testnet/package.json +++ b/scripts/init-testnet/package.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "@polkadot/api": "^9.3.3", - "@polkadot/keyring": "^12.3.2" + "@polkadot/keyring": "^12.3.2", + "ethers": "^6.10.0" } } From 112acfb03f66c4c8784fdde38dd0241ae27f9edf Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 7 Feb 2024 12:55:01 +0100 Subject: [PATCH 30/64] remove duplication for call length --- integration-tests/src/evm.rs | 3 +-- integration-tests/src/fee_calculation.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index cb76f544a..e2ccdb5dd 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -666,13 +666,12 @@ fn compare_fee_between_evm_and_native_omnipool_calls() { //Pre dispatch the native omnipool call - so withdrawring only the fees for the execution let info = omni_sell.get_dispatch_info(); - let len: usize = 146; //Just like on the UI assert_ok!( pallet_transaction_payment::ChargeTransactionPayment::::from(0).pre_dispatch( &AccountId::from(ALICE), &omni_sell, &info, - len, + crate::fee_calculation::SWAP_ENCODED_LEN as usize, ) ); diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs index f6f05f221..e414f0707 100644 --- a/integration-tests/src/fee_calculation.rs +++ b/integration-tests/src/fee_calculation.rs @@ -22,7 +22,7 @@ const DOT_UNITS: u128 = 10_000_000_000; const BTC_UNITS: u128 = 10_000_000; const ETH_UNITS: u128 = 1_000_000_000_000_000_000; const HDX_USD_SPOT_PRICE_IN_CENTS: Balance = 2; //1HDX =~ 2 CENTS; -const SWAP_ENCODED_LEN: u32 = 146; //We use this as this is what the UI send as length when omnipool swap is executed +pub const SWAP_ENCODED_LEN: u32 = 146; //We use this as this is what the UI send as length when omnipool swap is executed const HDX_USD_SPOT_PRICE: f64 = 0.038; //Current HDX price in USD on CoinGecko on 6th Feb, 2024 pub const ETH_USD_SPOT_PRICE: f64 = 2337.92; //Current HDX price in USD on CoinGecko on 6th Feb, 2024 From 863312a8a76eff5edec50938e9d94a596b03d671 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 8 Feb 2024 08:18:39 +0100 Subject: [PATCH 31/64] clean up in scripts --- scripts/init-testnet/evm/dispatch.ts | 17 ++---- scripts/init-testnet/evm/init_chain.ts | 72 -------------------------- 2 files changed, 3 insertions(+), 86 deletions(-) diff --git a/scripts/init-testnet/evm/dispatch.ts b/scripts/init-testnet/evm/dispatch.ts index a192bd963..98cff0395 100644 --- a/scripts/init-testnet/evm/dispatch.ts +++ b/scripts/init-testnet/evm/dispatch.ts @@ -26,6 +26,7 @@ async function main() { const dispatchContractAddress = '0x0000000000000000000000000000000000000401'; try { + // Omnipool sell call encoded const extrinsicData = '0x3b05000000000500000000a0724e18090000000000000000000000000000000000000000000000000000'; // Replace with your extrinsic data const nonce = await provider.getTransactionCount(wallet.address, 'latest'); @@ -38,21 +39,9 @@ async function main() { data: extrinsicData, }; - const signer = wallet.connect(provider); // Connect the wallet to the provider - const signedTx = await signer.signTransaction(tx); // Sign the transaction - //const txResponse = await provider.sendTransaction(signedTx); // Send the signed transaction - const signer2= wallet.connect(provider); // Connect the wallet to the provider + const signer= wallet.connect(provider); // Connect the wallet to the provider + await signer.sendTransaction(tx); - await signer2.sendTransaction(tx); - - //await signer.sendTransaction(tx); - /* const signedTx = await wallet.signTransaction(tx); - const txResponse = await provider.send(signedTx);*/ - - // console.log('Transaction Hash:', txResponse.hash); - - // const receipt = await txResponse.wait(); - //console.log('Transaction Receipt:', receipt); } catch (error) { console.error('Error:', error); } diff --git a/scripts/init-testnet/evm/init_chain.ts b/scripts/init-testnet/evm/init_chain.ts index 753b6dd87..2566e5c2d 100644 --- a/scripts/init-testnet/evm/init_chain.ts +++ b/scripts/init-testnet/evm/init_chain.ts @@ -2,52 +2,8 @@ const { ApiPromise, WsProvider } = require('@polkadot/api'); const { hexToU8a } = require('@polkadot/util'); const { encodeAddress, decodeAddress } = require('@polkadot/util-crypto'); -/*const { - isAddress, - getAddress, -} = require('@ethersproject/address') - -*/ const { Keyring } = require('@polkadot/keyring'); -/* -export class H160 { - static prefixBytes = Buffer.from("ETH\0") - address: string - - constructor(address: string) { - this.address = safeConvertAddressH160(address) ?? "" - } - - toAccount = () => { - const addressBytes = Buffer.from(this.address.slice(2), "hex") - return encodeAddress( - new Uint8Array( - Buffer.concat([H160.prefixBytes, addressBytes, Buffer.alloc(8)]), - ), - 63, - ) - } - - static fromAccount = (address: string) => { - const decodedBytes = decodeAddress(address) - const addressBytes = decodedBytes.slice(H160.prefixBytes.length, -8) - return ( - safeConvertAddressH160(Buffer.from(addressBytes).toString("hex")) ?? "" - ) - } -} - -export function safeConvertAddressH160(value: string): string | null { - try { - return getAddress(value?.toLowerCase()) - } catch { - return null - } -}*/ - - - async function main () { // Initialise the provider to connect to the local node //const provider = new WsProvider('wss://rpc.nice.hydration.cloud'); @@ -68,36 +24,8 @@ async function main () { const keyring = new Keyring({ type: 'sr25519' }); const alice = keyring.addFromUri('//Alice'); - /*await api.tx.assetRegistry.register( - "test token", - {"Token": 0}, - 1000, - 5, - {symbol: "ttt", decimals: 10}, - null, - null - ).signAndSend(alice, );*/ - let transactions = []; - //let evmUser = "7KATdGbFsc58BDyfV9ZtxHEYPt5icvS5itHcJh3yWYmpwG8k"; - //const evmUserAcc = keyring.addFromUri(evmUser); - - /*let balance = await api.query.system.account(alice.publicKey); - console.log(`Alice's HDX balance before tx ${balance.data.free}`); - - let weth = 20; - let wethBalance = await api.query.tokens.accounts(alice.publicKey, weth); - console.log(`Alice's HDX balance before tx ${wethBalance.free}`); - - const nonce = await api.rpc.system.accountNextIndex(alice.publicKey); - await api.tx.evm.withdraw(safeConvertAddressH160(alice.publicKey), "2000000000000").signAndSend(alice, { nonce }); - console.log("Evm tx done"); - - - balance = await api.query.system.account(alice.publicKey); - console.log(`Alice's HDX balance is after evm ${balance.data.free}`);*/ - assetRegistry(api, transactions); mintForAlice(api, transactions); initOmnipool(api, transactions) From 21ab100fb88366ab9fd421fb9d36bb625e8aba06 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 8 Feb 2024 15:02:37 +0100 Subject: [PATCH 32/64] clean up in tests --- integration-tests/src/evm.rs | 2 +- integration-tests/src/fee_calculation.rs | 106 ++++++----------------- integration-tests/src/non_native_fee.rs | 3 +- 3 files changed, 28 insertions(+), 83 deletions(-) diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index e2ccdb5dd..44586f76f 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -751,7 +751,7 @@ pub fn init_omnipol() { pub const DISPATCH_ADDR: H160 = addr(1025); pub fn gas_price() -> U256 { - U256::from(hydradx_runtime::evm::DEFAULT_BASE_FEE_PER_GAS) //We divide by three as we const `FEE_DIVIDER` set to 3 in system.rs. + U256::from(hydradx_runtime::evm::DEFAULT_BASE_FEE_PER_GAS) } fn create_dispatch_handle(data: Vec) -> MockHandle { diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs index e414f0707..7637276db 100644 --- a/integration-tests/src/fee_calculation.rs +++ b/integration-tests/src/fee_calculation.rs @@ -9,6 +9,7 @@ use hydradx_runtime::Tokens; use hydradx_runtime::TransactionPayment; use hydradx_runtime::EVM; use orml_traits::MultiCurrency; +use pallet_evm::FeeCalculator; use primitives::constants::currency::UNITS; use primitives::constants::time::HOURS; use primitives::{AssetId, Balance}; @@ -21,11 +22,11 @@ use xcm_emulator::TestExt; const DOT_UNITS: u128 = 10_000_000_000; const BTC_UNITS: u128 = 10_000_000; const ETH_UNITS: u128 = 1_000_000_000_000_000_000; -const HDX_USD_SPOT_PRICE_IN_CENTS: Balance = 2; //1HDX =~ 2 CENTS; pub const SWAP_ENCODED_LEN: u32 = 146; //We use this as this is what the UI send as length when omnipool swap is executed const HDX_USD_SPOT_PRICE: f64 = 0.038; //Current HDX price in USD on CoinGecko on 6th Feb, 2024 pub const ETH_USD_SPOT_PRICE: f64 = 2337.92; //Current HDX price in USD on CoinGecko on 6th Feb, 2024 +#[ignore] #[test] fn min_swap_fee() { TestNet::reset(); @@ -57,6 +58,7 @@ fn min_swap_fee() { }); } +#[ignore] #[test] fn max_swap_fee() { TestNet::reset(); @@ -86,22 +88,33 @@ fn max_swap_fee() { }); } +#[ignore] #[test] -fn fee_growth_simulator_starting_with_genesis_chain() { +fn substrate_and_evm_fee_growth_simulator_with_genesis_chain() { TestNet::reset(); Hydra::execute_with(|| { let prod_init_multiplier = FixedU128::from_u32(1); pallet_transaction_payment::pallet::NextFeeMultiplier::::put(prod_init_multiplier); + assert_ok!(hydradx_runtime::Currencies::update_balance( + hydradx_runtime::RuntimeOrigin::root(), + evm_account(), + HDX, + 1000000 * UNITS as i128, + )); + init_omnipool(); - init_oracle(); + //init_oracle(); let block_weight = hydradx_runtime::BlockWeights::get() .get(DispatchClass::Normal) .max_total .unwrap(); - for b in 2..=HOURS { + let mut nonce = 0; + + for b in 2..HOURS { + //=HOURS { hydradx_run_to_block(b); hydradx_runtime::System::set_block_consumed_resources(block_weight, 0); let call = @@ -114,57 +127,22 @@ fn fee_growth_simulator_starting_with_genesis_chain() { let info = call.get_dispatch_info(); let fee = TransactionPayment::compute_fee(SWAP_ENCODED_LEN, &info, 0); - let fee_in_cent = FixedU128::from(fee * HDX_USD_SPOT_PRICE_IN_CENTS).div(UNITS.into()); - - let next = TransactionPayment::next_fee_multiplier(); - - //let next = SlowAdjustingFeeUpdate::::convert(multiplier); - println!("Swap tx fee in cents: {fee_in_cent:?} at block {b:?} with multiplier: {next:?}"); - } - }); -} - -#[test] -fn fee_growth_simulator_with_idle_chain() { - TestNet::reset(); - - Hydra::execute_with(|| { - //We simulate that the chain has no activity so the MinimumMultiplier kept diverged to absolute minimum - pallet_transaction_payment::pallet::NextFeeMultiplier::::put( - hydradx_runtime::MinimumMultiplier::get(), - ); - - init_omnipool(); - init_oracle(); - let block_weight = hydradx_runtime::BlockWeights::get() - .get(DispatchClass::Normal) - .max_total - .unwrap(); - - for b in 2..=HOURS { - hydradx_run_to_block(b); - hydradx_runtime::System::set_block_consumed_resources(block_weight / 3, 0); - let call = - hydradx_runtime::RuntimeCall::Omnipool(pallet_omnipool::Call::::sell { - asset_in: HDX, - asset_out: 2, - amount: 10 * UNITS, - min_buy_amount: 10000, - }); - let info = call.get_dispatch_info(); - let fee = TransactionPayment::compute_fee(SWAP_ENCODED_LEN, &info, 0); - let fee_in_cent = FixedU128::from(fee * HDX_USD_SPOT_PRICE_IN_CENTS).div(UNITS.into()); + let fee_in_cent = (fee as f64 * HDX_USD_SPOT_PRICE) as f64 / 1000000000000.0; + let fee_in_cent = round(fee_in_cent); + let evm_fee_in_cent = round(get_evm_fee_in_cent(nonce)); let next = TransactionPayment::next_fee_multiplier(); - //let next = SlowAdjustingFeeUpdate::::convert(multiplier); - println!("Swap tx fee in cents: {fee_in_cent:?} at block {b:?} with multiplier: {next:?}"); + let gas_price = hydradx_runtime::DynamicEvmFee::min_gas_price(); + + println!("{b:?} - fee: ${fee_in_cent:?} - evm_fee: ${evm_fee_in_cent:?} - multiplier: {next:?} - gas {gas_price:?}"); + nonce = nonce + 1; } }); } -use pallet_evm::FeeCalculator; +#[ignore] #[test] fn substrate_and_evm_fee_growth_simulator_with_idle_chain() { TestNet::reset(); @@ -204,8 +182,6 @@ fn substrate_and_evm_fee_growth_simulator_with_idle_chain() { let info = call.get_dispatch_info(); let fee = TransactionPayment::compute_fee(SWAP_ENCODED_LEN, &info, 0); - //let fee_in_cent = FixedU128::from(fee * HDX_USD_SPOT_PRICE_IN_CENTS).div(UNITS.into()); - //let fee_in_cent = (fee * HDX_USD_SPOT_PRICE_IN_CENTS) as f64 / 1000000000000.0; let fee_in_cent = (fee as f64 * HDX_USD_SPOT_PRICE) as f64 / 1000000000000.0; let fee_in_cent = round(fee_in_cent); @@ -220,6 +196,7 @@ fn substrate_and_evm_fee_growth_simulator_with_idle_chain() { } }); } + pub fn get_evm_fee_in_cent(nonce: u128) -> f64 { let treasury_eth_balance = Tokens::free_balance(WETH, &Treasury::account_id()); @@ -287,37 +264,6 @@ fn init_omnipool() { Permill::from_percent(100), hydradx_runtime::Omnipool::protocol_account(), )); - - let dot_price = FixedU128::from_inner(25_650_000_000_000_000_000); - assert_ok!(hydradx_runtime::Omnipool::add_token( - hydradx_runtime::RuntimeOrigin::root(), - DOT, - dot_price, - Permill::from_percent(100), - AccountId::from(BOB), - )); - - let eth_price = FixedU128::from_inner(71_145_071_145_071); - assert_ok!(hydradx_runtime::Omnipool::add_token( - hydradx_runtime::RuntimeOrigin::root(), - ETH, - eth_price, - Permill::from_percent(100), - AccountId::from(BOB), - )); - - let btc_price = FixedU128::from_inner(9_647_109_647_109_650_000_000_000); - assert_ok!(hydradx_runtime::Omnipool::add_token( - hydradx_runtime::RuntimeOrigin::root(), - BTC, - btc_price, - Permill::from_percent(100), - AccountId::from(BOB), - )); - set_zero_reward_for_referrals(HDX); - set_zero_reward_for_referrals(DAI); - set_zero_reward_for_referrals(DOT); - set_zero_reward_for_referrals(ETH); } /// This function executes one sell and buy with HDX for all assets in the omnipool. This is necessary to diff --git a/integration-tests/src/non_native_fee.rs b/integration-tests/src/non_native_fee.rs index 83c64fec6..eb0f9161b 100644 --- a/integration-tests/src/non_native_fee.rs +++ b/integration-tests/src/non_native_fee.rs @@ -75,8 +75,7 @@ fn non_native_fee_payment_works_with_oracle_price_based_on_onchain_route() { ); let dave_balance = hydradx_runtime::Tokens::free_balance(DAI, &AccountId::from(DAVE)); - //TODO: something is off here, maybe no onchain route, or so, check it out - assert_eq!(dave_balance, 999_998_727_439_637_199_700); //Price based on oracle with onchain route + assert_eq!(dave_balance, 999_998_727_439_637_199_700); }); } From 47cb09e0c455e2b733126616ef66c10698088268 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 8 Feb 2024 15:18:46 +0100 Subject: [PATCH 33/64] add documnetation for dynamic evm fee pallet --- pallets/dynamic-evm-fee/README.md | 28 +++++++++++++++++++++- pallets/dynamic-evm-fee/src/lib.rs | 38 ++++++++++++++++++++++++++---- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/pallets/dynamic-evm-fee/README.md b/pallets/dynamic-evm-fee/README.md index 2c8924a2e..487450959 100644 --- a/pallets/dynamic-evm-fee/README.md +++ b/pallets/dynamic-evm-fee/README.md @@ -1 +1,27 @@ -# TODO: add readme \ No newline at end of file +# Dynamic EVM Fee + +## Overview + +The goal of this pallet to have EVM transaction fees in tandem with Substrate fees. + +This pallet enables dynamic adjustment of the EVM transaction fee, leveraging two primary metrics: +- Current network congestion +- The oracle price difference between ETH and HDX + +Fees are calculated with the production of each new block, ensuring responsiveness to changing network conditions. + +### Fee Adjustment Based on Network Congestion +The formula for adjusting fees in response to network congestion is as follows: +``` +BaseFeePerGas = DefaultBaseFeePerGas + (DefaultBaseFeePerGas * Multiplier * 3) +``` +- `DefaultBaseFeePerGas`: This represents the minimum fee payable for a transaction, set in pallet configuration. +- `Multiplier`: Derived from current network congestion levels, this multiplier is computed within the `pallet-transaction-payment`. + +### Fee Adjustment Based on ETH-HDX Price Fluctuations + +The transaction fee is also adjusted in accordance with in ETH-HDX oracle price change: +- When HDX increases in value against ETH, the fee is reduced accordingly. +- When HDX decreases in value against ETH, the fee is increased accordingly. + +This dual-criteria approach ensures that transaction fees remain fair and reflective of both market conditions and network demand. \ No newline at end of file diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index d3bda1efd..1fb68bd55 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -15,6 +15,34 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! # Dynamic EVM Fee +//! +//! ## Overview +//! +//! The goal of this pallet to have EVM transaction fees in tandem with Substrate fees. +//! +//! This pallet enables dynamic adjustment of the EVM transaction fee, leveraging two primary metrics: +//! - Current network congestion +//! - The oracle price difference between ETH and HDX +//! +//! Fees are calculated with the production of each new block, ensuring responsiveness to changing network conditions. +//! +//! ### Fee Adjustment Based on Network Congestion +//! The formula for adjusting fees in response to network congestion is as follows: +//! ``` +//! BaseFeePerGas = DefaultBaseFeePerGas + (DefaultBaseFeePerGas * Multiplier * 3) +//! ``` +//! - `DefaultBaseFeePerGas`: This represents the minimum fee payable for a transaction, set in pallet configuration. +//! - `Multiplier`: Derived from current network congestion levels, this multiplier is computed within the `pallet-transaction-payment`. +//! +//! ### Fee Adjustment Based on ETH-HDX Price Fluctuations +//! +//! The transaction fee is also adjusted in accordance with in ETH-HDX oracle price change: +//! - When HDX increases in value against ETH, the fee is reduced accordingly. +//! - When HDX decreases in value against ETH, the fee is increased accordingly. +//! +//! This dual-criteria approach ensures that transaction fees remain fair and reflective of both market conditions and network demand. + #![cfg_attr(not(feature = "std"), no_std)] #[cfg(test)] @@ -61,13 +89,13 @@ pub mod pallet { /// Default base fee per gas value. Used in genesis if no other value specified explicitly. type DefaultBaseFeePerGas: Get; - /// Multiplier provider + /// Transaction fee multiplier provider type Multiplier: MultiplierProvider; /// Native price oracle type NativePriceOracle: NativePriceOracle; - /// Eth Asset Id + /// WETH Asset Id #[pallet::constant] type WethAssetId: Get; @@ -111,7 +139,7 @@ pub mod pallet { }; let eth_hdx_price = FixedU128::from_rational(eth_hdx_price.n, eth_hdx_price.d); - let (price_diff, hdx_pumps_against_hdx) = if eth_hdx_price > ETH_HDX_REFERENCE_PRICE { + let (price_diff, hdx_pumps_against_eth) = if eth_hdx_price > ETH_HDX_REFERENCE_PRICE { (eth_hdx_price.saturating_sub(ETH_HDX_REFERENCE_PRICE), false) } else { (ETH_HDX_REFERENCE_PRICE.saturating_sub(eth_hdx_price), true) @@ -129,7 +157,7 @@ pub mod pallet { let evm_fee_change = percentage_change_permill.mul_floor(new_base_fee_per_gas); - if hdx_pumps_against_hdx { + if hdx_pumps_against_eth { new_base_fee_per_gas = new_base_fee_per_gas.saturating_sub(evm_fee_change); } else { new_base_fee_per_gas = new_base_fee_per_gas.saturating_add(evm_fee_change); @@ -148,8 +176,8 @@ pub mod pallet { } impl pallet_evm::FeeCalculator for Pallet { fn min_gas_price() -> (U256, Weight) { - // Return some meaningful gas price and weight let base_fee_per_gas = Self::base_evm_fee(); + (base_fee_per_gas.into(), T::WeightInfo::on_initialize()) } } From 033a4f6b24e83211e439b1877f1673e2399cf622 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 8 Feb 2024 15:23:44 +0100 Subject: [PATCH 34/64] cleaning up --- pallets/dynamic-evm-fee/README.md | 6 +++- .../src/benchmarking/dynamic_evm_fee.rs | 34 ------------------- runtime/hydradx/src/evm/mod.rs | 11 ------ runtime/hydradx/src/system.rs | 7 ++-- 4 files changed, 8 insertions(+), 50 deletions(-) diff --git a/pallets/dynamic-evm-fee/README.md b/pallets/dynamic-evm-fee/README.md index 487450959..20596d42d 100644 --- a/pallets/dynamic-evm-fee/README.md +++ b/pallets/dynamic-evm-fee/README.md @@ -24,4 +24,8 @@ The transaction fee is also adjusted in accordance with in ETH-HDX oracle price - When HDX increases in value against ETH, the fee is reduced accordingly. - When HDX decreases in value against ETH, the fee is increased accordingly. -This dual-criteria approach ensures that transaction fees remain fair and reflective of both market conditions and network demand. \ No newline at end of file +This dual-criteria approach ensures that transaction fees remain fair and reflective of both market conditions and network demand. + + +### FeeCalculator +The pallet implements `FeeCalculator` trait of pallet_evm to be used for EVM transactions \ No newline at end of file diff --git a/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs b/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs index 2d4bd3486..6ddec8246 100644 --- a/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs +++ b/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs @@ -96,40 +96,6 @@ runtime_benchmarks! { } use crate::Omnipool; use sp_runtime::Permill; -/* -use crate::Omnipool; -use sp_runtime::Permill; -const HDX: AssetId = 0; -const DAI: AssetId = 2; - -pub fn init() -> DispatchResult { - let stable_amount: Balance = 1_000_000_000_000_000u128; - let native_amount: Balance = 1_000_000_000_000_000u128; - let stable_price: FixedU128 = FixedU128::from((1, 2)); - let native_price: FixedU128 = FixedU128::from(1); - - let acc = Omnipool::protocol_account(); - - update_balance(DAI, &acc, stable_amount); - update_balance(HDX, &acc, native_amount); - - Omnipool::add_token( - RawOrigin::Root.into(), - HDX, - native_price, - Permill::from_percent(100), - acc.clone(), - )?; - Omnipool::add_token( - RawOrigin::Root.into(), - DAI, - stable_price, - Permill::from_percent(100), - acc, - )?; - - Ok(()) -}*/ fn create_xyk_pool(asset_a: AssetId, amount_a: Balance, asset_b: AssetId, amount_b: Balance) where diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index 46c951d90..a5f6af94b 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -113,16 +113,6 @@ parameter_types! { pub PostLogContent: pallet_ethereum::PostLogContent = pallet_ethereum::PostLogContent::BlockAndTxnHashes; } -/* -pub struct FixedGasPrice; //TODO: rename to DynamicGasPrice -impl FeeCalculator for FixedGasPrice { - fn min_gas_price() -> (U256, Weight) { - // Return some meaningful gas price and weight - let base_fee_per_gas = crate::DynamicEvmFee::base_evm_fee(); - (base_fee_per_gas.into(), Weight::from_parts(7u64, 0)) //TODO: add the weight once benchmarked - } -}*/ - pub struct TransactionPaymentMultiplier; impl MultiplierProvider for TransactionPaymentMultiplier { @@ -151,7 +141,6 @@ impl pallet_evm::Config for crate::Runtime { type ChainId = crate::EVMChainId; type Currency = WethCurrency; type FeeCalculator = crate::DynamicEvmFee; - //type FeeCalculator = crate::BaseFee; type FindAuthor = FindAuthorTruncated; type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type OnChargeTransaction = TransferEvmFees; diff --git a/runtime/hydradx/src/system.rs b/runtime/hydradx/src/system.rs index db98202ba..dff187d77 100644 --- a/runtime/hydradx/src/system.rs +++ b/runtime/hydradx/src/system.rs @@ -420,8 +420,7 @@ pub type SlowAdjustingFeeUpdate = pub struct WeightToFee; -//TODO: make constants for all fee related stuff -pub const FEE_DIVIDER: u128 = 6; // We use this to divide fee related constant as HDX price is high (~0.04$), but we want to reduce the fee price +pub const SUBSTRATE_FEE_DIVIDER: u128 = 6; // We use this to divide fee related constant as HDX price is high (~0.04$), but we want to reduce the fee price impl WeightToFeePolynomial for WeightToFee { type Balance = Balance; @@ -438,7 +437,7 @@ impl WeightToFeePolynomial for WeightToFee { /// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. fn polynomial() -> WeightToFeeCoefficients { // extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT - let p = CENTS / FEE_DIVIDER; // 1_000_000_000_000 + let p = CENTS / SUBSTRATE_FEE_DIVIDER; // 1_000_000_000_000 / SUBSTRATE_FEE_DIVIDER let q = 10 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); // 7_919_840_000 smallvec::smallvec![WeightToFeeCoefficient { degree: 1, @@ -450,7 +449,7 @@ impl WeightToFeePolynomial for WeightToFee { } parameter_types! { - pub const TransactionByteFee: Balance = 10 * MILLICENTS / FEE_DIVIDER; + pub const TransactionByteFee: Balance = 10 * MILLICENTS / SUBSTRATE_FEE_DIVIDER; /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less /// than this will decrease the weight and more will increase. pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); From 4935c101d0ee6821cf7fee43c093f2d725cfe0ef Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 8 Feb 2024 15:53:34 +0100 Subject: [PATCH 35/64] bump versions --- Cargo.lock | 4 ++-- integration-tests/Cargo.toml | 2 +- runtime/hydradx/Cargo.toml | 2 +- runtime/hydradx/src/lib.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7570822a..db49ec480 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4618,7 +4618,7 @@ dependencies = [ [[package]] name = "hydradx-runtime" -version = "206.0.0" +version = "207.0.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -11254,7 +11254,7 @@ dependencies = [ [[package]] name = "runtime-integration-tests" -version = "1.17.2" +version = "1.17.3" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index d408aa627..fc49434bf 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "runtime-integration-tests" -version = "1.17.2" +version = "1.17.3" description = "Integration tests" authors = ["GalacticCouncil"] edition = "2021" diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index c991f80e8..ec976a281 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-runtime" -version = "206.0.0" +version = "207.0.0" authors = ["GalacticCouncil"] edition = "2021" license = "Apache 2.0" diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index f7e8ccbe4..55b1c5726 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -107,7 +107,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("hydradx"), impl_name: create_runtime_str!("hydradx"), authoring_version: 1, - spec_version: 206, + spec_version: 207, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From db6c45585f67a8ed169022532507322aee645108 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 8 Feb 2024 16:19:14 +0100 Subject: [PATCH 36/64] fix formatting in doc --- pallets/dynamic-evm-fee/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 1fb68bd55..72d552994 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -29,9 +29,9 @@ //! //! ### Fee Adjustment Based on Network Congestion //! The formula for adjusting fees in response to network congestion is as follows: -//! ``` -//! BaseFeePerGas = DefaultBaseFeePerGas + (DefaultBaseFeePerGas * Multiplier * 3) -//! ``` +//! +//! BaseFeePerGas = DefaultBaseFeePerGas + (DefaultBaseFeePerGas * Multiplier * 3 +//! //! - `DefaultBaseFeePerGas`: This represents the minimum fee payable for a transaction, set in pallet configuration. //! - `Multiplier`: Derived from current network congestion levels, this multiplier is computed within the `pallet-transaction-payment`. //! From 19ebdf2d2aae546234af1a840ac537778cf7e64f Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 9 Feb 2024 09:16:49 +0100 Subject: [PATCH 37/64] make clippy happy --- integration-tests/src/cross_chain_transfer.rs | 2 +- integration-tests/src/fee_calculation.rs | 97 ++----------------- pallets/dynamic-evm-fee/src/lib.rs | 2 +- runtime/hydradx/src/tests.rs | 1 - 4 files changed, 10 insertions(+), 92 deletions(-) diff --git a/integration-tests/src/cross_chain_transfer.rs b/integration-tests/src/cross_chain_transfer.rs index 57ad2ec22..86f40a10a 100644 --- a/integration-tests/src/cross_chain_transfer.rs +++ b/integration-tests/src/cross_chain_transfer.rs @@ -336,7 +336,7 @@ fn claim_trapped_asset_should_work() { Hydra::execute_with(|| { assert_eq!( hydradx_runtime::Tokens::free_balance(1, &AccountId::from(BOB)), - 1029_959_811_596_766 //1000 * UNITS + 30 * UNITS - fee + 1_029_959_811_596_766 //1000 * UNITS + 30 * UNITS - fee ); let origin = MultiLocation::new(1, X1(Parachain(ACALA_PARA_ID))); diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs index 7637276db..e66c66720 100644 --- a/integration-tests/src/fee_calculation.rs +++ b/integration-tests/src/fee_calculation.rs @@ -12,16 +12,12 @@ use orml_traits::MultiCurrency; use pallet_evm::FeeCalculator; use primitives::constants::currency::UNITS; use primitives::constants::time::HOURS; -use primitives::{AssetId, Balance}; use sp_core::Encode; use sp_core::U256; use sp_runtime::{FixedU128, Permill}; use test_utils::assert_eq_approx; use xcm_emulator::TestExt; -const DOT_UNITS: u128 = 10_000_000_000; -const BTC_UNITS: u128 = 10_000_000; -const ETH_UNITS: u128 = 1_000_000_000_000_000_000; pub const SWAP_ENCODED_LEN: u32 = 146; //We use this as this is what the UI send as length when omnipool swap is executed const HDX_USD_SPOT_PRICE: f64 = 0.038; //Current HDX price in USD on CoinGecko on 6th Feb, 2024 pub const ETH_USD_SPOT_PRICE: f64 = 2337.92; //Current HDX price in USD on CoinGecko on 6th Feb, 2024 @@ -51,7 +47,7 @@ fn min_swap_fee() { assert_eq_approx!( fee_in_cent, - FixedU128::from_float(0.009909846329778000), + FixedU128::from_float(0.009_909_846_329_778), tolerance, "The min fee should be ~0.01$ (1 cent)" ); @@ -81,7 +77,7 @@ fn max_swap_fee() { let tolerance = FixedU128::from((2, (UNITS / 10_000))); assert_eq_approx!( fee_in_cent, - FixedU128::from_float(10.008401718494404694), + FixedU128::from_float(10.008_401_718_494_405), tolerance, "The max fee should be ~1000 cent (10$)" ); @@ -105,15 +101,12 @@ fn substrate_and_evm_fee_growth_simulator_with_genesis_chain() { )); init_omnipool(); - //init_oracle(); let block_weight = hydradx_runtime::BlockWeights::get() .get(DispatchClass::Normal) .max_total .unwrap(); - let mut nonce = 0; - - for b in 2..HOURS { + for (nonce, b) in (2..HOURS).enumerate() { //=HOURS { hydradx_run_to_block(b); hydradx_runtime::System::set_block_consumed_resources(block_weight, 0); @@ -128,16 +121,15 @@ fn substrate_and_evm_fee_growth_simulator_with_genesis_chain() { let info = call.get_dispatch_info(); let fee = TransactionPayment::compute_fee(SWAP_ENCODED_LEN, &info, 0); - let fee_in_cent = (fee as f64 * HDX_USD_SPOT_PRICE) as f64 / 1000000000000.0; + let fee_in_cent = (fee as f64 * HDX_USD_SPOT_PRICE) / 1000000000000.0; let fee_in_cent = round(fee_in_cent); - let evm_fee_in_cent = round(get_evm_fee_in_cent(nonce)); + let evm_fee_in_cent = round(get_evm_fee_in_cent(nonce as u128)); let next = TransactionPayment::next_fee_multiplier(); let gas_price = hydradx_runtime::DynamicEvmFee::min_gas_price(); println!("{b:?} - fee: ${fee_in_cent:?} - evm_fee: ${evm_fee_in_cent:?} - multiplier: {next:?} - gas {gas_price:?}"); - nonce = nonce + 1; } }); } @@ -160,15 +152,12 @@ fn substrate_and_evm_fee_growth_simulator_with_idle_chain() { )); init_omnipool(); - //init_oracle(); let block_weight = hydradx_runtime::BlockWeights::get() .get(DispatchClass::Normal) .max_total .unwrap(); - let mut nonce = 0; - - for b in 2..HOURS { + for (nonce, b) in (2..HOURS).enumerate() { //=HOURS { hydradx_run_to_block(b); hydradx_runtime::System::set_block_consumed_resources(block_weight, 0); @@ -183,16 +172,15 @@ fn substrate_and_evm_fee_growth_simulator_with_idle_chain() { let info = call.get_dispatch_info(); let fee = TransactionPayment::compute_fee(SWAP_ENCODED_LEN, &info, 0); - let fee_in_cent = (fee as f64 * HDX_USD_SPOT_PRICE) as f64 / 1000000000000.0; + let fee_in_cent = (fee as f64 * HDX_USD_SPOT_PRICE) / 1000000000000.0; let fee_in_cent = round(fee_in_cent); - let evm_fee_in_cent = round(get_evm_fee_in_cent(nonce)); + let evm_fee_in_cent = round(get_evm_fee_in_cent(nonce as u128)); let next = TransactionPayment::next_fee_multiplier(); let gas_price = hydradx_runtime::DynamicEvmFee::min_gas_price(); println!("{b:?} - fee: ${fee_in_cent:?} - evm_fee: ${evm_fee_in_cent:?} - multiplier: {next:?} - gas {gas_price:?}"); - nonce = nonce + 1; } }); } @@ -237,15 +225,6 @@ fn round(fee_in_cent: f64) -> f64 { (fee_in_cent * rounder).round() / rounder } -fn set_balance(who: hydradx_runtime::AccountId, currency: AssetId, amount: i128) { - assert_ok!(hydradx_runtime::Currencies::update_balance( - hydradx_runtime::RuntimeOrigin::root(), - who, - currency, - amount, - )); -} - fn init_omnipool() { let native_price = FixedU128::from_inner(1201500000000000); let stable_price = FixedU128::from_inner(45_000_000_000); @@ -265,63 +244,3 @@ fn init_omnipool() { hydradx_runtime::Omnipool::protocol_account(), )); } - -/// This function executes one sell and buy with HDX for all assets in the omnipool. This is necessary to -/// oracle have a prices for the assets. -/// NOTE: It's necessary to change parachain block to oracle have prices. -fn init_oracle() { - let trader = DAVE; - - set_balance(trader.into(), HDX, 1_000 * UNITS as i128); - set_balance(trader.into(), DOT, 1_000 * DOT_UNITS as i128); - set_balance(trader.into(), ETH, 1_000 * ETH_UNITS as i128); - set_balance(trader.into(), BTC, 1_000 * BTC_UNITS as i128); - - assert_ok!(hydradx_runtime::Omnipool::sell( - hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), - DOT, - HDX, - 2 * DOT_UNITS, - 0, - )); - - assert_ok!(hydradx_runtime::Omnipool::buy( - hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), - DOT, - HDX, - 2 * DOT_UNITS, - u128::MAX - )); - - assert_ok!(hydradx_runtime::Omnipool::sell( - hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), - ETH, - HDX, - 2 * ETH_UNITS, - 0, - )); - - assert_ok!(hydradx_runtime::Omnipool::buy( - hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), - ETH, - HDX, - 2 * ETH_UNITS, - u128::MAX - )); - - assert_ok!(hydradx_runtime::Omnipool::sell( - hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), - BTC, - HDX, - 2 * BTC_UNITS, - 0, - )); - - assert_ok!(hydradx_runtime::Omnipool::buy( - hydradx_runtime::RuntimeOrigin::signed(DAVE.into()), - BTC, - HDX, - 2 * BTC_UNITS, - u128::MAX - )); -} diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 72d552994..02b3236bf 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -178,6 +178,6 @@ impl pallet_evm::FeeCalculator for Pallet { fn min_gas_price() -> (U256, Weight) { let base_fee_per_gas = Self::base_evm_fee(); - (base_fee_per_gas.into(), T::WeightInfo::on_initialize()) + (base_fee_per_gas, T::WeightInfo::on_initialize()) } } diff --git a/runtime/hydradx/src/tests.rs b/runtime/hydradx/src/tests.rs index 4449cd6cb..0367d2097 100644 --- a/runtime/hydradx/src/tests.rs +++ b/runtime/hydradx/src/tests.rs @@ -5,7 +5,6 @@ use primitives::constants::{ }; use codec::Encode; -use frame_support::traits::OnInitialize; use frame_support::{ dispatch::{DispatchClass, GetDispatchInfo}, sp_runtime::{traits::Convert, FixedPointNumber}, From 6d35ebd6e50a65284612d9cd269c32a39339c717 Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 9 Feb 2024 09:35:23 +0100 Subject: [PATCH 38/64] make clippy happy --- .../src/benchmarking/dynamic_evm_fee.rs | 74 ++----------------- 1 file changed, 5 insertions(+), 69 deletions(-) diff --git a/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs b/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs index 6ddec8246..0c31ecb58 100644 --- a/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs +++ b/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs @@ -22,30 +22,16 @@ use frame_benchmarking::BenchmarkError; use frame_support::assert_ok; use frame_support::traits::{OnFinalize, OnInitialize}; use frame_system::RawOrigin; -use hydradx_traits::router::PoolType; -use hydradx_traits::router::RouteProvider; -use hydradx_traits::PriceOracle; use orml_benchmarking::runtime_benchmarks; use orml_traits::MultiCurrencyExtended; -use pallet_route_executor::MAX_NUMBER_OF_TRADES; -use primitives::{BlockNumber, Price}; +use primitives::BlockNumber; use sp_runtime::traits::SaturatedConversion; -use sp_runtime::{DispatchResult, FixedU128}; +use sp_runtime::FixedU128; -type MultiPaymentPallet = pallet_transaction_multi_payment::Pallet; type DynamicEvmFeePallet = pallet_dynamic_evm_fee::Pallet; -type XykPallet = pallet_xyk::Pallet; -type Router = pallet_route_executor::Pallet; use crate::evm::WETH_ASSET_LOCATION; -use hydradx_traits::router::AssetPair; -use hydradx_traits::router::Trade; -use hydradx_traits::OraclePeriod; use pallet_dynamic_evm_fee::BaseFeePerGas; -const SEED: u32 = 1; - -const UNITS: Balance = 1_000_000_000_000; - pub fn update_balance(currency_id: AssetId, who: &AccountId, balance: Balance) { assert_ok!(>::update_balance( currency_id, @@ -79,16 +65,16 @@ runtime_benchmarks! { update_balance(0, &owner, 1_000_000_000_000_000_u128); // Add the token to the pool - Omnipool::add_token(RawOrigin::Root.into(), token_id, token_price, Permill::from_percent(100), owner.clone())?; + Omnipool::add_token(RawOrigin::Root.into(), token_id, token_price, Permill::from_percent(100), owner)?; let seller: AccountId = account("seller", 3, 1); update_balance(0, &seller, 500_000_000_000_000_u128); - Omnipool::sell(RawOrigin::Signed(seller.clone()).into(), 0, token_id, 10000000000000, 0)?; + Omnipool::sell(RawOrigin::Signed(seller).into(), 0, token_id, 10000000000000, 0)?; set_period(10); let base_fee_per_gas = >::get(); }: { - DynamicEvmFeePallet::::on_initialize(1u32.into()) + DynamicEvmFeePallet::::on_initialize(1u32) } verify{ assert!(>::get() != base_fee_per_gas); @@ -97,56 +83,6 @@ runtime_benchmarks! { use crate::Omnipool; use sp_runtime::Permill; -fn create_xyk_pool(asset_a: AssetId, amount_a: Balance, asset_b: AssetId, amount_b: Balance) -where - ::RuntimeOrigin: core::convert::From>, -{ - let maker: AccountId = account("xyk-maker", 0, SEED); - - assert_ok!(Currencies::update_balance( - RawOrigin::Root.into(), - maker.clone(), - asset_a, - amount_a as i128, - )); - assert_ok!(Currencies::update_balance( - RawOrigin::Root.into(), - maker.clone(), - asset_b, - amount_b as i128, - )); - - assert_ok!(XykPallet::::create_pool( - RawOrigin::Signed(maker).into(), - asset_a, - amount_a, - asset_b, - amount_b, - )); -} - -fn xyk_sell(asset_a: AssetId, asset_b: AssetId, amount_a: Balance) -where - ::RuntimeOrigin: core::convert::From>, -{ - let maker: AccountId = account("xyk-seller", 0, SEED); - - assert_ok!(Currencies::update_balance( - RawOrigin::Root.into(), - maker.clone(), - asset_a, - amount_a as i128, - )); - assert_ok!(XykPallet::::sell( - RawOrigin::Signed(maker).into(), - asset_a, - asset_b, - amount_a, - u128::MIN, - false - )); -} - fn set_period(to: u32) { while System::block_number() < Into::::into(to) { let b = System::block_number(); From 71d689018f7efb8505b5f8b5583687b5bcd53e2f Mon Sep 17 00:00:00 2001 From: mrq Date: Tue, 20 Feb 2024 12:10:52 +0100 Subject: [PATCH 39/64] make checksum supports mac os --- Makefile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 84973e399..d1d6080df 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,10 @@ +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Darwin) + SHASUM = shasum -a 256 +else + SHASUM = sha256sum +endif + .PHONY: build build: cargo build --release --locked @@ -56,9 +63,9 @@ docker: docker build -t hydra-dx . checksum: - sha256sum target/release/hydradx > target/release/hydradx.sha256 + $(SHASUM) target/release/hydradx > target/release/hydradx.sha256 cp target/release/wbuild/hydradx-runtime/hydradx_runtime.compact.compressed.wasm target/release/ - sha256sum target/release/hydradx_runtime.compact.compressed.wasm > target/release/hydradx_runtime.compact.compressed.wasm.sha256 + $(SHASUM) target/release/hydradx_runtime.compact.compressed.wasm > target/release/hydradx_runtime.compact.compressed.wasm.sha256 release: build checksum From 5ec1d4962da3bcb3b1bf11634f85d6f89b9b5c68 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 20 Feb 2024 16:10:30 +0100 Subject: [PATCH 40/64] refactor and suggestion --- pallets/dynamic-evm-fee/src/lib.rs | 44 +++++++++++++++++------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 02b3236bf..61c72d95b 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -67,6 +67,7 @@ use sp_runtime::FixedU128; use sp_runtime::Permill; use sp_runtime::Saturating; +//TODO: consider moving to a config pub const ETH_HDX_REFERENCE_PRICE: FixedU128 = FixedU128::from_inner(16420844565569051996); //Current onchain ETH price on at block 4418935 pub const MAX_BASE_FEE_PER_GAS: u128 = 17304992000u128; @@ -89,6 +90,7 @@ pub mod pallet { /// Default base fee per gas value. Used in genesis if no other value specified explicitly. type DefaultBaseFeePerGas: Get; + //TODO: jus use Get<> /// Transaction fee multiplier provider type Multiplier: MultiplierProvider; @@ -129,9 +131,9 @@ pub mod pallet { let multiplier = T::Multiplier::next(); let mut new_base_fee_per_gas = T::DefaultBaseFeePerGas::get() - + multiplier + .saturating_add(multiplier .saturating_mul_int(T::DefaultBaseFeePerGas::get()) - .saturating_mul(3); + .saturating_mul(3)); let Some(eth_hdx_price) = T::NativePriceOracle::price(T::WethAssetId::get()) else { log::warn!(target: "runtime::dynamic-evm-fee", "Could not get ETH-HDX price from oracle"); @@ -139,39 +141,43 @@ pub mod pallet { }; let eth_hdx_price = FixedU128::from_rational(eth_hdx_price.n, eth_hdx_price.d); - let (price_diff, hdx_pumps_against_eth) = if eth_hdx_price > ETH_HDX_REFERENCE_PRICE { - (eth_hdx_price.saturating_sub(ETH_HDX_REFERENCE_PRICE), false) - } else { - (ETH_HDX_REFERENCE_PRICE.saturating_sub(eth_hdx_price), true) - }; + // | P1 - P2 | (P1 + P2) / 2 * 100 - let Some(percentage_change) = price_diff - .saturating_mul(FixedU128::saturating_from_integer(100)) - .const_checked_div(ETH_HDX_REFERENCE_PRICE) else { - log::warn!(target: "runtime::dynamic-evm-fee", "Unexpected error: Could not calculate percentage change"); - return; + let sum = eth_hdx_price.saturating_add(ETH_HDX_REFERENCE_PRICE); + + let diff = if eth_hdx_price > ETH_HDX_REFERENCE_PRICE { + eth_hdx_price.saturating_sub(ETH_HDX_REFERENCE_PRICE) + }else{ + ETH_HDX_REFERENCE_PRICE.saturating_sub(eth_hdx_price) }; - let percentage_change_permill = - Permill::from_rational(percentage_change.into_inner(), FixedU128::DIV * 100); + // TODO: ensure that sum > 1, just to be safe + // or use checked div + let pdiff = diff / (sum / FixedU128::from(2)); - let evm_fee_change = percentage_change_permill.mul_floor(new_base_fee_per_gas); + let evm_fee_change = pdiff.saturating_mul_int(new_base_fee_per_gas); - if hdx_pumps_against_eth { + if eth_hdx_price < crate::ETH_HDX_REFERENCE_PRICE { new_base_fee_per_gas = new_base_fee_per_gas.saturating_sub(evm_fee_change); } else { new_base_fee_per_gas = new_base_fee_per_gas.saturating_add(evm_fee_change); } + // Note that clamp panics!! if min > max + if min_base_fee_per_gas > MAX_BASE_FEE_PER_GAS { + // safe safe safe + //TODO: add integrity test for this + return; + } new_base_fee_per_gas = new_base_fee_per_gas.clamp(min_base_fee_per_gas, MAX_BASE_FEE_PER_GAS); *old_base_fee_per_gas = U256::from(new_base_fee_per_gas); }); - let mut weight = Weight::default(); - weight.saturating_accrue(T::WeightInfo::on_initialize()); - weight + T::WeightInfo::on_initialize() } + + } } impl pallet_evm::FeeCalculator for Pallet { From 65b02543924986ece329cc0169f831e78b0defd1 Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 21 Feb 2024 11:04:44 +0100 Subject: [PATCH 41/64] fix tests as we corrected the price difference change calculation --- pallets/dynamic-evm-fee/src/tests/on_initialize.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs index f117b411e..c075d9902 100644 --- a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs +++ b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs @@ -38,7 +38,7 @@ fn should_decrease_evm_fee_when_hdx_pumping_10percent_against_eth() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(24071998)); + assert_eq!(new_base_fee, U256::from(23931226)); }); } @@ -54,14 +54,14 @@ fn should_not_change_when_price_pumps_then_remains_same_in_consquent_block() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(24071998)); + assert_eq!(new_base_fee, U256::from(23931226)); //Act DynamicEvmFee::on_initialize(2); //Assert let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(24071998)); + assert_eq!(new_base_fee, U256::from(23931226)); }); } @@ -75,7 +75,7 @@ fn should_decrease_evm_fee_when_hdx_pumping_1percent_against_eth() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(26479198)); + assert_eq!(new_base_fee, U256::from(26477854)); }); } @@ -89,6 +89,6 @@ fn should_increase_evm_fee_when_hdx_dumping_10percent_against_eth() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(29421303)); + assert_eq!(new_base_fee, U256::from(29293965)); }); } From be4709b94555c4c2a7aa1bd75f8d35ce6db09977 Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 21 Feb 2024 11:32:58 +0100 Subject: [PATCH 42/64] made unsafe operations safe --- pallets/dynamic-evm-fee/src/lib.rs | 42 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 61c72d95b..065ef73f9 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -62,11 +62,11 @@ use frame_system::pallet_prelude::BlockNumberFor; use hydra_dx_math::ema::EmaPrice; use hydradx_traits::NativePriceOracle; use sp_core::U256; +use sp_runtime::traits::CheckedDiv; use sp_runtime::FixedPointNumber; use sp_runtime::FixedU128; use sp_runtime::Permill; use sp_runtime::Saturating; - //TODO: consider moving to a config pub const ETH_HDX_REFERENCE_PRICE: FixedU128 = FixedU128::from_inner(16420844565569051996); //Current onchain ETH price on at block 4418935 pub const MAX_BASE_FEE_PER_GAS: u128 = 17304992000u128; @@ -130,10 +130,11 @@ pub mod pallet { let min_base_fee_per_gas = T::DefaultBaseFeePerGas::get().saturating_div(10); let multiplier = T::Multiplier::next(); - let mut new_base_fee_per_gas = T::DefaultBaseFeePerGas::get() - .saturating_add(multiplier + let mut new_base_fee_per_gas = T::DefaultBaseFeePerGas::get().saturating_add( + multiplier .saturating_mul_int(T::DefaultBaseFeePerGas::get()) - .saturating_mul(3)); + .saturating_mul(3), + ); let Some(eth_hdx_price) = T::NativePriceOracle::price(T::WethAssetId::get()) else { log::warn!(target: "runtime::dynamic-evm-fee", "Could not get ETH-HDX price from oracle"); @@ -145,30 +146,30 @@ pub mod pallet { let sum = eth_hdx_price.saturating_add(ETH_HDX_REFERENCE_PRICE); - let diff = if eth_hdx_price > ETH_HDX_REFERENCE_PRICE { + let diff = if eth_hdx_price > ETH_HDX_REFERENCE_PRICE { eth_hdx_price.saturating_sub(ETH_HDX_REFERENCE_PRICE) - }else{ + } else { ETH_HDX_REFERENCE_PRICE.saturating_sub(eth_hdx_price) }; - // TODO: ensure that sum > 1, just to be safe - // or use checked div - let pdiff = diff / (sum / FixedU128::from(2)); + let Some(denominator) = sum.checked_div(&FixedU128::from(2)) else { + log::warn!(target: "runtime::dynamic-evm-fee", "Error calculating denominator for price difference, sum: {:?}", sum); + return; + }; - let evm_fee_change = pdiff.saturating_mul_int(new_base_fee_per_gas); + let Some(price_difference) = diff.checked_div(&denominator) else { + log::warn!(target: "runtime::dynamic-evm-fee", "Error calculating price difference, diff: {:?}, denominator: {:?}", diff, denominator); + return; + }; - if eth_hdx_price < crate::ETH_HDX_REFERENCE_PRICE { + let evm_fee_change = price_difference.saturating_mul_int(new_base_fee_per_gas); + + if eth_hdx_price < ETH_HDX_REFERENCE_PRICE { new_base_fee_per_gas = new_base_fee_per_gas.saturating_sub(evm_fee_change); } else { new_base_fee_per_gas = new_base_fee_per_gas.saturating_add(evm_fee_change); } - // Note that clamp panics!! if min > max - if min_base_fee_per_gas > MAX_BASE_FEE_PER_GAS { - // safe safe safe - //TODO: add integrity test for this - return; - } new_base_fee_per_gas = new_base_fee_per_gas.clamp(min_base_fee_per_gas, MAX_BASE_FEE_PER_GAS); *old_base_fee_per_gas = U256::from(new_base_fee_per_gas); @@ -177,7 +178,12 @@ pub mod pallet { T::WeightInfo::on_initialize() } - + fn integrity_test() { + assert!( + T::DefaultBaseFeePerGas::get() < MAX_BASE_FEE_PER_GAS, + "DefaultBaseFeePerGas should be less than MAX_BASE_FEE_PER_GAS, otherwise it fails when we clamp when we bound the value" + ); + } } } impl pallet_evm::FeeCalculator for Pallet { From 0fae3fdf87f9b78c32dbe7ad49063aaac066b4ad Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 21 Feb 2024 11:40:47 +0100 Subject: [PATCH 43/64] renamings --- pallets/dynamic-evm-fee/src/lib.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 065ef73f9..b74889f53 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -142,16 +142,15 @@ pub mod pallet { }; let eth_hdx_price = FixedU128::from_rational(eth_hdx_price.n, eth_hdx_price.d); - // | P1 - P2 | (P1 + P2) / 2 * 100 - - let sum = eth_hdx_price.saturating_add(ETH_HDX_REFERENCE_PRICE); - - let diff = if eth_hdx_price > ETH_HDX_REFERENCE_PRICE { - eth_hdx_price.saturating_sub(ETH_HDX_REFERENCE_PRICE) - } else { + //Price difference: |P1 - P2| / ((P1 + P2) / 2) + let is_hdx_pumping = eth_hdx_price < ETH_HDX_REFERENCE_PRICE; + let diff = if is_hdx_pumping { ETH_HDX_REFERENCE_PRICE.saturating_sub(eth_hdx_price) + } else { + eth_hdx_price.saturating_sub(ETH_HDX_REFERENCE_PRICE) }; + let sum = eth_hdx_price.saturating_add(ETH_HDX_REFERENCE_PRICE); let Some(denominator) = sum.checked_div(&FixedU128::from(2)) else { log::warn!(target: "runtime::dynamic-evm-fee", "Error calculating denominator for price difference, sum: {:?}", sum); return; @@ -164,7 +163,7 @@ pub mod pallet { let evm_fee_change = price_difference.saturating_mul_int(new_base_fee_per_gas); - if eth_hdx_price < ETH_HDX_REFERENCE_PRICE { + if is_hdx_pumping { new_base_fee_per_gas = new_base_fee_per_gas.saturating_sub(evm_fee_change); } else { new_base_fee_per_gas = new_base_fee_per_gas.saturating_add(evm_fee_change); From 2bc0aee7f75a5fe4609242b81be0e31eba88744b Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 21 Feb 2024 12:01:25 +0100 Subject: [PATCH 44/64] remove custom trait as we can solve it with a normat Get trait --- pallets/dynamic-evm-fee/src/lib.rs | 6 ++---- pallets/dynamic-evm-fee/src/tests/mock.rs | 5 ++--- pallets/dynamic-evm-fee/src/types.rs | 5 ----- runtime/hydradx/src/evm/mod.rs | 5 ++--- 4 files changed, 6 insertions(+), 15 deletions(-) delete mode 100644 pallets/dynamic-evm-fee/src/types.rs diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index b74889f53..0e494a66e 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -48,14 +48,12 @@ #[cfg(test)] mod tests; -pub mod types; pub mod weights; // Re-export pallet items so that they can be accessed from the crate namespace. pub use pallet::*; pub use weights::WeightInfo; -use crate::types::MultiplierProvider; use codec::HasCompact; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::BlockNumberFor; @@ -92,7 +90,7 @@ pub mod pallet { //TODO: jus use Get<> /// Transaction fee multiplier provider - type Multiplier: MultiplierProvider; + type Multiplier: Get; /// Native price oracle type NativePriceOracle: NativePriceOracle; @@ -128,7 +126,7 @@ pub mod pallet { //TODO: add a integration test with price change from trades so oracle price changes BaseFeePerGas::::mutate(|old_base_fee_per_gas| { let min_base_fee_per_gas = T::DefaultBaseFeePerGas::get().saturating_div(10); - let multiplier = T::Multiplier::next(); + let multiplier = T::Multiplier::get(); let mut new_base_fee_per_gas = T::DefaultBaseFeePerGas::get().saturating_add( multiplier diff --git a/pallets/dynamic-evm-fee/src/tests/mock.rs b/pallets/dynamic-evm-fee/src/tests/mock.rs index 0e6dc4d27..44bd91979 100644 --- a/pallets/dynamic-evm-fee/src/tests/mock.rs +++ b/pallets/dynamic-evm-fee/src/tests/mock.rs @@ -20,7 +20,6 @@ use crate::Config; use hydra_dx_math::types::Ratio; use crate as dynamic_evm_fee; -use crate::types::MultiplierProvider; use frame_support::{ parameter_types, traits::{Everything, Get, Nothing}, @@ -123,8 +122,8 @@ impl system::Config for Test { pub struct MultiplierProviderMock; -impl MultiplierProvider for MultiplierProviderMock { - fn next() -> Multiplier { +impl Get for MultiplierProviderMock { + fn get() -> Multiplier { MULTIPLIER.with(|v| *v.borrow()) } } diff --git a/pallets/dynamic-evm-fee/src/types.rs b/pallets/dynamic-evm-fee/src/types.rs deleted file mode 100644 index 3e9cb97c0..000000000 --- a/pallets/dynamic-evm-fee/src/types.rs +++ /dev/null @@ -1,5 +0,0 @@ -use sp_runtime::FixedU128; - -pub trait MultiplierProvider { - fn next() -> FixedU128; -} diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index a5f6af94b..66b305441 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -33,7 +33,6 @@ use frame_support::{ use hex_literal::hex; use hydradx_adapters::{AssetFeeOraclePriceProvider, OraclePriceProvider}; use orml_tokens::CurrencyAdapter; -use pallet_dynamic_evm_fee::types::MultiplierProvider; use pallet_evm::EnsureAddressTruncated; use pallet_transaction_multi_payment::{DepositAll, DepositFee, TransferEvmFees}; use pallet_transaction_payment::Multiplier; @@ -115,8 +114,8 @@ parameter_types! { pub struct TransactionPaymentMultiplier; -impl MultiplierProvider for TransactionPaymentMultiplier { - fn next() -> Multiplier { +impl Get for TransactionPaymentMultiplier { + fn get() -> Multiplier { crate::TransactionPayment::next_fee_multiplier() } } From ff6c4b52bd83cefcb314f5b197602f4b31a82ec0 Mon Sep 17 00:00:00 2001 From: dmoka Date: Wed, 21 Feb 2024 12:20:56 +0100 Subject: [PATCH 45/64] renaming --- pallets/dynamic-evm-fee/src/lib.rs | 5 ++--- pallets/dynamic-evm-fee/src/tests/mock.rs | 2 +- runtime/hydradx/src/evm/mod.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 0e494a66e..210019b6a 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -88,9 +88,8 @@ pub mod pallet { /// Default base fee per gas value. Used in genesis if no other value specified explicitly. type DefaultBaseFeePerGas: Get; - //TODO: jus use Get<> /// Transaction fee multiplier provider - type Multiplier: Get; + type FeeMultiplier: Get; /// Native price oracle type NativePriceOracle: NativePriceOracle; @@ -126,7 +125,7 @@ pub mod pallet { //TODO: add a integration test with price change from trades so oracle price changes BaseFeePerGas::::mutate(|old_base_fee_per_gas| { let min_base_fee_per_gas = T::DefaultBaseFeePerGas::get().saturating_div(10); - let multiplier = T::Multiplier::get(); + let multiplier = T::FeeMultiplier::get(); let mut new_base_fee_per_gas = T::DefaultBaseFeePerGas::get().saturating_add( multiplier diff --git a/pallets/dynamic-evm-fee/src/tests/mock.rs b/pallets/dynamic-evm-fee/src/tests/mock.rs index 44bd91979..842482e7f 100644 --- a/pallets/dynamic-evm-fee/src/tests/mock.rs +++ b/pallets/dynamic-evm-fee/src/tests/mock.rs @@ -147,7 +147,7 @@ impl Get for DefaultBaseDFeePerGas { impl Config for Test { type AssetId = AssetId; type DefaultBaseFeePerGas = DefaultBaseDFeePerGas; - type Multiplier = MultiplierProviderMock; + type FeeMultiplier = MultiplierProviderMock; type NativePriceOracle = NativePriceOracleMock; type WethAssetId = HdxAssetId; type WeightInfo = (); diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index 66b305441..241b4d2db 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -172,7 +172,7 @@ parameter_types! { impl pallet_dynamic_evm_fee::Config for crate::Runtime { type AssetId = AssetId; type DefaultBaseFeePerGas = DefaultBaseFeePerGas; - type Multiplier = TransactionPaymentMultiplier; + type FeeMultiplier = TransactionPaymentMultiplier; type NativePriceOracle = AssetFeeOraclePriceProvider< NativeAssetId, crate::MultiTransactionPayment, From 3f5d0eb176a06a4d96b7e9e481e63985d92df7b1 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 22 Feb 2024 12:03:52 +0100 Subject: [PATCH 46/64] update cargo --- Cargo.lock | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 090a22160..4a26488e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4669,6 +4669,7 @@ dependencies = [ "pallet-dca", "pallet-democracy 4.1.0", "pallet-duster", + "pallet-dynamic-evm-fee", "pallet-dynamic-fees", "pallet-elections-phragmen", "pallet-ema-oracle", @@ -7496,6 +7497,33 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "pallet-dynamic-evm-fee" +version = "1.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "hydra-dx-math", + "hydradx-traits", + "log", + "orml-tokens", + "orml-traits", + "pallet-balances", + "pallet-currencies", + "pallet-evm", + "pallet-transaction-payment", + "parity-scale-codec", + "primitives", + "scale-info", + "sp-api", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "test-utils", +] + [[package]] name = "pallet-dynamic-fees" version = "1.0.2" @@ -11331,7 +11359,7 @@ dependencies = [ [[package]] name = "runtime-integration-tests" -version = "1.18.1" +version = "1.18.2" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -11375,6 +11403,7 @@ dependencies = [ "pallet-dca", "pallet-democracy 4.1.0", "pallet-duster", + "pallet-dynamic-evm-fee", "pallet-dynamic-fees", "pallet-elections-phragmen", "pallet-ema-oracle", @@ -11433,6 +11462,7 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", + "test-utils", "tokio", "xcm-emulator", ] From 6fcb43de8b800be268f42191c7ac77ba90fd3246 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 22 Feb 2024 12:14:05 +0100 Subject: [PATCH 47/64] fix fee test for account binding as fee has been cut by 5/6 --- integration-tests/src/evm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index a5ddc35a3..72bf858d3 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -244,8 +244,8 @@ mod account_conversion { let fee_raw = hydradx_runtime::TransactionPayment::compute_fee_details(len, &info, 0); let fee = fee_raw.final_fee(); - // simple test that the fee is approximately 10 HDX - assert!(fee / UNITS == 10); + // simple test that the fee is approximately 10/6 HDX (it was originally 10 HDX, but we divided the fee by 6 in the config) + assert_eq!(fee / UNITS, 10 / 6); }); } From 994b9be5f4ada9fbf65dfd7b51a2d0c270e6d722 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 22 Feb 2024 15:33:17 +0100 Subject: [PATCH 48/64] update eth hdx price --- pallets/dynamic-evm-fee/src/lib.rs | 15 ++++++++++----- pallets/dynamic-evm-fee/src/tests/mock.rs | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 210019b6a..45cfc9750 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -65,8 +65,8 @@ use sp_runtime::FixedPointNumber; use sp_runtime::FixedU128; use sp_runtime::Permill; use sp_runtime::Saturating; -//TODO: consider moving to a config -pub const ETH_HDX_REFERENCE_PRICE: FixedU128 = FixedU128::from_inner(16420844565569051996); //Current onchain ETH price on at block 4418935 + +pub const ETH_HDX_REFERENCE_PRICE: FixedU128 = FixedU128::from_inner(8945857934143137845); //Current onchain ETH price on at block #4,534,103 pub const MAX_BASE_FEE_PER_GAS: u128 = 17304992000u128; #[frame_support::pallet] @@ -139,7 +139,12 @@ pub mod pallet { }; let eth_hdx_price = FixedU128::from_rational(eth_hdx_price.n, eth_hdx_price.d); - //Price difference: |P1 - P2| / ((P1 + P2) / 2) + //Percentage difference: |P1 - P2| / ((P1 + P2) / 2) + if eth_hdx_price == 0.into() || ETH_HDX_REFERENCE_PRICE == 0.into() { + log::warn!(target: "runtime::dynamic-evm-fee", "ETH-HDX price is zero, could not calculate price percentage difference"); + return; + } + let is_hdx_pumping = eth_hdx_price < ETH_HDX_REFERENCE_PRICE; let diff = if is_hdx_pumping { ETH_HDX_REFERENCE_PRICE.saturating_sub(eth_hdx_price) @@ -149,12 +154,12 @@ pub mod pallet { let sum = eth_hdx_price.saturating_add(ETH_HDX_REFERENCE_PRICE); let Some(denominator) = sum.checked_div(&FixedU128::from(2)) else { - log::warn!(target: "runtime::dynamic-evm-fee", "Error calculating denominator for price difference, sum: {:?}", sum); + log::warn!(target: "runtime::dynamic-evm-fee", "Error calculating denominator for price percentage difference, sum: {:?}", sum); return; }; let Some(price_difference) = diff.checked_div(&denominator) else { - log::warn!(target: "runtime::dynamic-evm-fee", "Error calculating price difference, diff: {:?}, denominator: {:?}", diff, denominator); + log::warn!(target: "runtime::dynamic-evm-fee", "Error calculating price percentage difference, diff: {:?}, denominator: {:?}", diff, denominator); return; }; diff --git a/pallets/dynamic-evm-fee/src/tests/mock.rs b/pallets/dynamic-evm-fee/src/tests/mock.rs index 842482e7f..dda046849 100644 --- a/pallets/dynamic-evm-fee/src/tests/mock.rs +++ b/pallets/dynamic-evm-fee/src/tests/mock.rs @@ -57,7 +57,7 @@ pub const HIGH_VALUE_CURRENCY: AssetId = 7000; pub const HIGH_ED: Balance = 5; -pub const DEFAULT_ETH_HDX_ORACLE_PRICE: Ratio = Ratio::new(16420844565569051996, FixedU128::DIV); +pub const DEFAULT_ETH_HDX_ORACLE_PRICE: Ratio = Ratio::new(8945857934143137845, FixedU128::DIV); thread_local! { static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::zero()); From 20d2fce0a4b2f885f87e1a3b20049e5114cce868 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 22 Feb 2024 15:34:27 +0100 Subject: [PATCH 49/64] bump main version --- Cargo.lock | 2 +- runtime/hydradx/Cargo.toml | 2 +- runtime/hydradx/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a26488e0..74a098e77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4619,7 +4619,7 @@ dependencies = [ [[package]] name = "hydradx-runtime" -version = "212.0.0" +version = "213.0.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index ed9f6895b..0b05bb081 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-runtime" -version = "212.0.0" +version = "213.0.0" authors = ["GalacticCouncil"] edition = "2021" license = "Apache 2.0" diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 2f999742b..1a10058bb 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -107,7 +107,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("hydradx"), impl_name: create_runtime_str!("hydradx"), authoring_version: 1, - spec_version: 212, + spec_version: 213, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 42a2a2fcb3a566d22b9a8d66112aa1521bc5ee2a Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 22 Feb 2024 15:37:11 +0100 Subject: [PATCH 50/64] update lock file --- Cargo.lock | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 49c701cbc..cbed517e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4621,7 +4621,7 @@ dependencies = [ [[package]] name = "hydradx-runtime" -version = "214.0.0" +version = "215.0.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -4671,6 +4671,7 @@ dependencies = [ "pallet-dca", "pallet-democracy 4.1.0", "pallet-duster", + "pallet-dynamic-evm-fee", "pallet-dynamic-fees", "pallet-elections-phragmen", "pallet-ema-oracle", @@ -7498,6 +7499,33 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "pallet-dynamic-evm-fee" +version = "1.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "hydra-dx-math", + "hydradx-traits", + "log", + "orml-tokens", + "orml-traits", + "pallet-balances", + "pallet-currencies", + "pallet-evm", + "pallet-transaction-payment", + "parity-scale-codec", + "primitives", + "scale-info", + "sp-api", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "test-utils", +] + [[package]] name = "pallet-dynamic-fees" version = "1.0.2" @@ -11333,7 +11361,7 @@ dependencies = [ [[package]] name = "runtime-integration-tests" -version = "1.19.1" +version = "1.19.2" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -11377,6 +11405,7 @@ dependencies = [ "pallet-dca", "pallet-democracy 4.1.0", "pallet-duster", + "pallet-dynamic-evm-fee", "pallet-dynamic-fees", "pallet-elections-phragmen", "pallet-ema-oracle", @@ -11435,6 +11464,7 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", + "test-utils", "tokio", "xcm-emulator", ] From 9c97b79ec1e275f33b305197e168a58a80f3d4e4 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 22 Feb 2024 15:40:50 +0100 Subject: [PATCH 51/64] revert back makefile as we prolly made a mistake when merging --- Makefile | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index d1d6080df..d51132178 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,3 @@ -UNAME_S := $(shell uname -s) -ifeq ($(UNAME_S),Darwin) - SHASUM = shasum -a 256 -else - SHASUM = sha256sum -endif - .PHONY: build build: cargo build --release --locked @@ -63,13 +56,13 @@ docker: docker build -t hydra-dx . checksum: - $(SHASUM) target/release/hydradx > target/release/hydradx.sha256 + sha256sum target/release/hydradx > target/release/hydradx.sha256 cp target/release/wbuild/hydradx-runtime/hydradx_runtime.compact.compressed.wasm target/release/ - $(SHASUM) target/release/hydradx_runtime.compact.compressed.wasm > target/release/hydradx_runtime.compact.compressed.wasm.sha256 + sha256sum target/release/hydradx_runtime.compact.compressed.wasm > target/release/hydradx_runtime.compact.compressed.wasm.sha256 release: build checksum all: clippy build-benchmarks test-benchmarks test build checksum chopstics: release - npx @acala-network/chopsticks xcm --parachain=launch-configs/chopsticks/hydradx.yml --parachain=launch-configs/chopsticks/assethub.yml + npx @acala-network/chopsticks xcm --parachain=launch-configs/chopsticks/hydradx.yml --parachain=launch-configs/chopsticks/assethub.yml \ No newline at end of file From 3d41fd6c0135a8220aa1ff41fc3fdaf2534fb1f0 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 22 Feb 2024 16:55:42 +0100 Subject: [PATCH 52/64] retune fees as the price changed so we set a new reference --- integration-tests/src/cross_chain_transfer.rs | 19 +++++++------------ integration-tests/src/evm.rs | 4 ++-- integration-tests/src/fee_calculation.rs | 4 ++-- integration-tests/src/non_native_fee.rs | 4 ++-- runtime/hydradx/src/evm/mod.rs | 2 +- runtime/hydradx/src/system.rs | 4 ++-- 6 files changed, 16 insertions(+), 21 deletions(-) diff --git a/integration-tests/src/cross_chain_transfer.rs b/integration-tests/src/cross_chain_transfer.rs index f3fa10ed8..00abde8a5 100644 --- a/integration-tests/src/cross_chain_transfer.rs +++ b/integration-tests/src/cross_chain_transfer.rs @@ -53,15 +53,13 @@ fn hydra_should_receive_asset_when_transferred_from_polkadot_relay_chain() { ); }); - let fees = 66980672057; Hydra::execute_with(|| { - assert_eq!( - hydradx_runtime::Tokens::free_balance(1, &hydradx_runtime::Treasury::account_id()), - fees - ); + let fee = hydradx_runtime::Tokens::free_balance(1, &hydradx_runtime::Treasury::account_id()); + assert!(fee > 0, "Fees is not sent to treasury"); + assert_eq!( hydradx_runtime::Tokens::free_balance(1, &AccountId::from(BOB)), - BOB_INITIAL_NATIVE_BALANCE + 300 * UNITS - fees + BOB_INITIAL_NATIVE_BALANCE + 300 * UNITS - fee ); }); } @@ -141,16 +139,13 @@ fn hydra_should_receive_asset_when_transferred_from_acala() { ); }); - let fee = 53584537646; Hydra::execute_with(|| { + let fee = hydradx_runtime::Tokens::free_balance(ACA, &hydradx_runtime::Treasury::account_id()); + assert!(fee > 0, "Fees is not sent to treasury"); assert_eq!( hydradx_runtime::Tokens::free_balance(ACA, &AccountId::from(BOB)), 30 * UNITS - fee ); - assert_eq!( - hydradx_runtime::Tokens::free_balance(ACA, &hydradx_runtime::Treasury::account_id()), - fee // fees should go to treasury - ); }); } @@ -331,7 +326,7 @@ fn claim_trapped_asset_should_work() { Hydra::execute_with(|| { assert_eq!( hydradx_runtime::Tokens::free_balance(1, &AccountId::from(BOB)), - 1_029_959_811_596_766 //1000 * UNITS + 30 * UNITS - fee + 1_029_939_717_395_149 //1000 * UNITS + 30 * UNITS - fee ); let origin = MultiLocation::new(1, X1(Parachain(ACALA_PARA_ID))); diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index 72bf858d3..d5434af38 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -244,8 +244,8 @@ mod account_conversion { let fee_raw = hydradx_runtime::TransactionPayment::compute_fee_details(len, &info, 0); let fee = fee_raw.final_fee(); - // simple test that the fee is approximately 10/6 HDX (it was originally 10 HDX, but we divided the fee by 6 in the config) - assert_eq!(fee / UNITS, 10 / 6); + // simple test that the fee is approximately 10/4 HDX (it was originally 10 HDX, but we divided the fee by 4 in the config) + assert_eq!(fee / UNITS, 10 / 4); }); } diff --git a/integration-tests/src/fee_calculation.rs b/integration-tests/src/fee_calculation.rs index e66c66720..c9f5ad059 100644 --- a/integration-tests/src/fee_calculation.rs +++ b/integration-tests/src/fee_calculation.rs @@ -19,8 +19,8 @@ use test_utils::assert_eq_approx; use xcm_emulator::TestExt; pub const SWAP_ENCODED_LEN: u32 = 146; //We use this as this is what the UI send as length when omnipool swap is executed -const HDX_USD_SPOT_PRICE: f64 = 0.038; //Current HDX price in USD on CoinGecko on 6th Feb, 2024 -pub const ETH_USD_SPOT_PRICE: f64 = 2337.92; //Current HDX price in USD on CoinGecko on 6th Feb, 2024 +const HDX_USD_SPOT_PRICE: f64 = 0.0266; //Current HDX price in USD on CoinGecko on 22th Feb, 2024 +pub const ETH_USD_SPOT_PRICE: f64 = 2907.92; //Current HDX price in USD on CoinGecko on 22th Feb, 2024 #[ignore] #[test] diff --git a/integration-tests/src/non_native_fee.rs b/integration-tests/src/non_native_fee.rs index eb0f9161b..8eb455bbe 100644 --- a/integration-tests/src/non_native_fee.rs +++ b/integration-tests/src/non_native_fee.rs @@ -46,7 +46,7 @@ fn non_native_fee_payment_works_with_oracle_price_based_on_onchain_route() { ) ); let bob_balance = hydradx_runtime::Tokens::free_balance(BTC, &AccountId::from(BOB)); - assert_eq!(bob_balance, 999994); + assert_eq!(bob_balance, 999991); assert_ok!(hydradx_runtime::Balances::force_set_balance( hydradx_runtime::RuntimeOrigin::root(), @@ -75,7 +75,7 @@ fn non_native_fee_payment_works_with_oracle_price_based_on_onchain_route() { ); let dave_balance = hydradx_runtime::Tokens::free_balance(DAI, &AccountId::from(DAVE)); - assert_eq!(dave_balance, 999_998_727_439_637_199_700); + assert_eq!(dave_balance, 999_998_091_159_455_519_200); }); } diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index fa9413ada..6c3647cbe 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -55,7 +55,7 @@ pub const GAS_PER_SECOND: u64 = 40_000_000; const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; // Fixed gas price of 0.019 gwei per gas -pub const DEFAULT_BASE_FEE_PER_GAS: u128 = 19_000_000; +pub const DEFAULT_BASE_FEE_PER_GAS: u128 = 15_000_000; parameter_types! { // We allow for a 75% fullness of a 0.5s block diff --git a/runtime/hydradx/src/system.rs b/runtime/hydradx/src/system.rs index fdf1ee832..c218f2cc0 100644 --- a/runtime/hydradx/src/system.rs +++ b/runtime/hydradx/src/system.rs @@ -423,7 +423,7 @@ pub type SlowAdjustingFeeUpdate = pub struct WeightToFee; -pub const SUBSTRATE_FEE_DIVIDER: u128 = 6; // We use this to divide fee related constant as HDX price is high (~0.04$), but we want to reduce the fee price +pub const SUBSTRATE_FEE_DIVIDER: u128 = 4; // We use this to divide fee related constant as HDX price is high (~0.26$), but we want to reduce the fee price impl WeightToFeePolynomial for WeightToFee { type Balance = Balance; @@ -463,7 +463,7 @@ parameter_types! { /// that combined with `AdjustmentVariable`, we can recover from the minimum. pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1000u128); /// The maximum amount of the multiplier. - pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(335); + pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(320); } impl pallet_transaction_payment::Config for Runtime { From fd96ce04fa9a39d4991ca945caed444f4bad13d8 Mon Sep 17 00:00:00 2001 From: dmoka Date: Thu, 22 Feb 2024 22:43:03 +0100 Subject: [PATCH 53/64] add failing test for max evm fee - WIP as does not work yet --- pallets/dynamic-evm-fee/src/lib.rs | 3 +- pallets/dynamic-evm-fee/src/tests/mock.rs | 2 +- .../src/tests/on_initialize.rs | 45 +++++++++++++++---- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 45cfc9750..aee6049ee 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -67,7 +67,7 @@ use sp_runtime::Permill; use sp_runtime::Saturating; pub const ETH_HDX_REFERENCE_PRICE: FixedU128 = FixedU128::from_inner(8945857934143137845); //Current onchain ETH price on at block #4,534,103 -pub const MAX_BASE_FEE_PER_GAS: u128 = 17304992000u128; +pub const MAX_BASE_FEE_PER_GAS: u128 = 14415000000u128; #[frame_support::pallet] pub mod pallet { @@ -122,7 +122,6 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(_: BlockNumberFor) -> Weight { - //TODO: add a integration test with price change from trades so oracle price changes BaseFeePerGas::::mutate(|old_base_fee_per_gas| { let min_base_fee_per_gas = T::DefaultBaseFeePerGas::get().saturating_div(10); let multiplier = T::FeeMultiplier::get(); diff --git a/pallets/dynamic-evm-fee/src/tests/mock.rs b/pallets/dynamic-evm-fee/src/tests/mock.rs index dda046849..6f097bad3 100644 --- a/pallets/dynamic-evm-fee/src/tests/mock.rs +++ b/pallets/dynamic-evm-fee/src/tests/mock.rs @@ -140,7 +140,7 @@ pub struct DefaultBaseDFeePerGas; impl Get for DefaultBaseDFeePerGas { fn get() -> u128 { - 80_000_000 / 3 + 15_000_000 } } diff --git a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs index c075d9902..a0d9453a0 100644 --- a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs +++ b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs @@ -4,26 +4,28 @@ use frame_support::traits::OnInitialize; use hydra_dx_math::types::Ratio; use pallet_transaction_payment::Multiplier; use sp_core::U256; - +use sp_runtime::FixedPointNumber; +use sp_runtime::FixedU128; +use sp_runtime::Saturating; #[test] fn should_return_default_base_fee_when_min_multiplier() { ExtBuilder::default().build().execute_with(|| { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(26746664)); + assert_eq!(new_base_fee, U256::from(15045000)); }); } #[test] fn should_increase_evm_fee_with_max_multiplier() { ExtBuilder::default().build().execute_with(|| { - set_multiplier(Multiplier::from_rational(335, 1)); + set_multiplier(Multiplier::from_rational(320, 1)); DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(17304992000u128)); + assert_eq!(new_base_fee, U256::from(14415000000u128)); }); } @@ -38,7 +40,7 @@ fn should_decrease_evm_fee_when_hdx_pumping_10percent_against_eth() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(23931226)); + assert_eq!(new_base_fee, U256::from(13461316)); }); } @@ -54,14 +56,14 @@ fn should_not_change_when_price_pumps_then_remains_same_in_consquent_block() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(23931226)); + assert_eq!(new_base_fee, U256::from(13461316)); //Act DynamicEvmFee::on_initialize(2); //Assert let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(23931226)); + assert_eq!(new_base_fee, U256::from(13461316)); }); } @@ -75,7 +77,7 @@ fn should_decrease_evm_fee_when_hdx_pumping_1percent_against_eth() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(26477854)); + assert_eq!(new_base_fee, U256::from(14893794)); }); } @@ -89,6 +91,31 @@ fn should_increase_evm_fee_when_hdx_dumping_10percent_against_eth() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(29293965)); + assert_eq!(new_base_fee, U256::from(16477857)); + }); +} + +#[test] +fn evm_fee_should_go_to_minimum_when_price_pumped_a_lot() { + ExtBuilder::default().build().execute_with(|| { + set_oracle_price(Ratio::new( + DEFAULT_ETH_HDX_ORACLE_PRICE.n * 1 / 100, + DEFAULT_ETH_HDX_ORACLE_PRICE.d, + )); + DynamicEvmFee::on_initialize(1); + + let new_base_fee = DynamicEvmFee::base_evm_fee(); + assert_eq!(new_base_fee, U256::from(1500000)); + }); +} + +#[test] +fn evm_fee_should_go_to_maximum_when_price_dumped_a_lot() { + ExtBuilder::default().build().execute_with(|| { + set_oracle_price(Ratio::new(8945857934143137845 * 10000, FixedU128::DIV)); + DynamicEvmFee::on_initialize(1); + + let new_base_fee = DynamicEvmFee::base_evm_fee(); + assert_eq!(new_base_fee, U256::from(14415000000u128)); // TODO: this should be }); } From 0a65440c753af5ed807739f0c6ecb95db0cbfe2d Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 23 Feb 2024 16:07:23 +0100 Subject: [PATCH 54/64] fix and simplify evm scaling based on price --- pallets/dynamic-evm-fee/src/lib.rs | 34 ++---------------- .../src/tests/on_initialize.rs | 36 ++++++++++--------- runtime/hydradx/src/evm/mod.rs | 2 +- 3 files changed, 24 insertions(+), 48 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index aee6049ee..615bb88ba 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -137,38 +137,10 @@ pub mod pallet { return; }; let eth_hdx_price = FixedU128::from_rational(eth_hdx_price.n, eth_hdx_price.d); + let price_diff = + FixedU128::from_rational(eth_hdx_price.into_inner(), ETH_HDX_REFERENCE_PRICE.into_inner()); - //Percentage difference: |P1 - P2| / ((P1 + P2) / 2) - if eth_hdx_price == 0.into() || ETH_HDX_REFERENCE_PRICE == 0.into() { - log::warn!(target: "runtime::dynamic-evm-fee", "ETH-HDX price is zero, could not calculate price percentage difference"); - return; - } - - let is_hdx_pumping = eth_hdx_price < ETH_HDX_REFERENCE_PRICE; - let diff = if is_hdx_pumping { - ETH_HDX_REFERENCE_PRICE.saturating_sub(eth_hdx_price) - } else { - eth_hdx_price.saturating_sub(ETH_HDX_REFERENCE_PRICE) - }; - - let sum = eth_hdx_price.saturating_add(ETH_HDX_REFERENCE_PRICE); - let Some(denominator) = sum.checked_div(&FixedU128::from(2)) else { - log::warn!(target: "runtime::dynamic-evm-fee", "Error calculating denominator for price percentage difference, sum: {:?}", sum); - return; - }; - - let Some(price_difference) = diff.checked_div(&denominator) else { - log::warn!(target: "runtime::dynamic-evm-fee", "Error calculating price percentage difference, diff: {:?}, denominator: {:?}", diff, denominator); - return; - }; - - let evm_fee_change = price_difference.saturating_mul_int(new_base_fee_per_gas); - - if is_hdx_pumping { - new_base_fee_per_gas = new_base_fee_per_gas.saturating_sub(evm_fee_change); - } else { - new_base_fee_per_gas = new_base_fee_per_gas.saturating_add(evm_fee_change); - } + new_base_fee_per_gas = price_diff.saturating_mul_int(new_base_fee_per_gas); new_base_fee_per_gas = new_base_fee_per_gas.clamp(min_base_fee_per_gas, MAX_BASE_FEE_PER_GAS); diff --git a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs index a0d9453a0..456eeb3d7 100644 --- a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs +++ b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs @@ -7,6 +7,7 @@ use sp_core::U256; use sp_runtime::FixedPointNumber; use sp_runtime::FixedU128; use sp_runtime::Saturating; + #[test] fn should_return_default_base_fee_when_min_multiplier() { ExtBuilder::default().build().execute_with(|| { @@ -30,17 +31,17 @@ fn should_increase_evm_fee_with_max_multiplier() { } #[test] -fn should_decrease_evm_fee_when_hdx_pumping_10percent_against_eth() { +fn should_increase_evm_fee_when_hdx_pumping_10percent_against_eth() { ExtBuilder::default().build().execute_with(|| { set_oracle_price(Ratio::new( - DEFAULT_ETH_HDX_ORACLE_PRICE.n * 90 / 100, + DEFAULT_ETH_HDX_ORACLE_PRICE.n * 110 / 100, DEFAULT_ETH_HDX_ORACLE_PRICE.d, )); DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(13461316)); + assert_eq!(new_base_fee, U256::from(16549500)); }); } @@ -49,54 +50,54 @@ fn should_not_change_when_price_pumps_then_remains_same_in_consquent_block() { ExtBuilder::default().build().execute_with(|| { //Arrange set_oracle_price(Ratio::new( - DEFAULT_ETH_HDX_ORACLE_PRICE.n * 90 / 100, + DEFAULT_ETH_HDX_ORACLE_PRICE.n * 110 / 100, DEFAULT_ETH_HDX_ORACLE_PRICE.d, )); DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(13461316)); + assert_eq!(new_base_fee, U256::from(16549500)); //Act DynamicEvmFee::on_initialize(2); //Assert let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(13461316)); + assert_eq!(new_base_fee, U256::from(16549500)); }); } #[test] -fn should_decrease_evm_fee_when_hdx_pumping_1percent_against_eth() { +fn should_increase_evm_fee_when_hdx_pumping_1percent_against_eth() { ExtBuilder::default().build().execute_with(|| { set_oracle_price(Ratio::new( - DEFAULT_ETH_HDX_ORACLE_PRICE.n * 99 / 100, + DEFAULT_ETH_HDX_ORACLE_PRICE.n * 101 / 100, DEFAULT_ETH_HDX_ORACLE_PRICE.d, )); DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(14893794)); + assert_eq!(new_base_fee, U256::from(15195450)); }); } #[test] -fn should_increase_evm_fee_when_hdx_dumping_10percent_against_eth() { +fn should_decrease_evm_fee_when_hdx_dumping_10percent_against_eth() { ExtBuilder::default().build().execute_with(|| { set_oracle_price(Ratio::new( - DEFAULT_ETH_HDX_ORACLE_PRICE.n * 110 / 100, + DEFAULT_ETH_HDX_ORACLE_PRICE.n * 90 / 100, DEFAULT_ETH_HDX_ORACLE_PRICE.d, )); DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(16477857)); + assert_eq!(new_base_fee, U256::from(13540500)); }); } #[test] -fn evm_fee_should_go_to_minimum_when_price_pumped_a_lot() { +fn evm_fee_should_go_to_minimum_when_hdx_dumps_a_alot() { ExtBuilder::default().build().execute_with(|| { set_oracle_price(Ratio::new( DEFAULT_ETH_HDX_ORACLE_PRICE.n * 1 / 100, @@ -110,12 +111,15 @@ fn evm_fee_should_go_to_minimum_when_price_pumped_a_lot() { } #[test] -fn evm_fee_should_go_to_maximum_when_price_dumped_a_lot() { +fn evm_fee_should_go_to_maximum_when_hdx_pumps_a_lot() { ExtBuilder::default().build().execute_with(|| { - set_oracle_price(Ratio::new(8945857934143137845 * 10000, FixedU128::DIV)); + set_oracle_price(Ratio::new( + DEFAULT_ETH_HDX_ORACLE_PRICE.n * 1000, + DEFAULT_ETH_HDX_ORACLE_PRICE.d, + )); DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(14415000000u128)); // TODO: this should be + assert_eq!(new_base_fee, U256::from(14415000000u128)); }); } diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index 6c3647cbe..53344ab60 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -54,7 +54,7 @@ pub const GAS_PER_SECOND: u64 = 40_000_000; // Approximate ratio of the amount of Weight per Gas. const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; -// Fixed gas price of 0.019 gwei per gas +// Fixed gas price of 0.015 gwei per gas pub const DEFAULT_BASE_FEE_PER_GAS: u128 = 15_000_000; parameter_types! { From d76ae4306e7d148720a4f9270ad201fc1eea9d7d Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 23 Feb 2024 16:17:17 +0100 Subject: [PATCH 55/64] introduce configs for min and max base fee per gas so we can safely check if the min is smalle so will never panic --- pallets/dynamic-evm-fee/src/lib.rs | 13 +++++++++---- pallets/dynamic-evm-fee/src/tests/mock.rs | 16 ++++++++++++++++ runtime/hydradx/src/evm/mod.rs | 4 ++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 615bb88ba..db1a5780c 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -67,7 +67,6 @@ use sp_runtime::Permill; use sp_runtime::Saturating; pub const ETH_HDX_REFERENCE_PRICE: FixedU128 = FixedU128::from_inner(8945857934143137845); //Current onchain ETH price on at block #4,534,103 -pub const MAX_BASE_FEE_PER_GAS: u128 = 14415000000u128; #[frame_support::pallet] pub mod pallet { @@ -85,6 +84,12 @@ pub mod pallet { + MaxEncodedLen + TypeInfo; + /// Minimum base fee per gas value. Used to bound the base fee per gas in min direction. + type MinBaseFeePerGas: Get; + + /// Maximum base fee per gas value. Used to bound the base fee per gas in max direction. + type MaxBaseFeePerGas: Get; + /// Default base fee per gas value. Used in genesis if no other value specified explicitly. type DefaultBaseFeePerGas: Get; @@ -123,7 +128,6 @@ pub mod pallet { impl Hooks> for Pallet { fn on_initialize(_: BlockNumberFor) -> Weight { BaseFeePerGas::::mutate(|old_base_fee_per_gas| { - let min_base_fee_per_gas = T::DefaultBaseFeePerGas::get().saturating_div(10); let multiplier = T::FeeMultiplier::get(); let mut new_base_fee_per_gas = T::DefaultBaseFeePerGas::get().saturating_add( @@ -142,7 +146,8 @@ pub mod pallet { new_base_fee_per_gas = price_diff.saturating_mul_int(new_base_fee_per_gas); - new_base_fee_per_gas = new_base_fee_per_gas.clamp(min_base_fee_per_gas, MAX_BASE_FEE_PER_GAS); + new_base_fee_per_gas = + new_base_fee_per_gas.clamp(T::MinBaseFeePerGas::get(), T::MaxBaseFeePerGas::get()); *old_base_fee_per_gas = U256::from(new_base_fee_per_gas); }); @@ -152,7 +157,7 @@ pub mod pallet { fn integrity_test() { assert!( - T::DefaultBaseFeePerGas::get() < MAX_BASE_FEE_PER_GAS, + T::MinBaseFeePerGas::get() < T::MaxBaseFeePerGas::get(), "DefaultBaseFeePerGas should be less than MAX_BASE_FEE_PER_GAS, otherwise it fails when we clamp when we bound the value" ); } diff --git a/pallets/dynamic-evm-fee/src/tests/mock.rs b/pallets/dynamic-evm-fee/src/tests/mock.rs index 6f097bad3..8f900b042 100644 --- a/pallets/dynamic-evm-fee/src/tests/mock.rs +++ b/pallets/dynamic-evm-fee/src/tests/mock.rs @@ -144,8 +144,24 @@ impl Get for DefaultBaseDFeePerGas { } } +pub struct MinBaseFeePerGas; +impl Get for MinBaseFeePerGas { + fn get() -> u128 { + 15_000_000 / 10 + } +} + +pub struct MaxBaseFeePerGas; +impl Get for MaxBaseFeePerGas { + fn get() -> u128 { + 14415000000 + } +} + impl Config for Test { type AssetId = AssetId; + type MinBaseFeePerGas = MinBaseFeePerGas; + type MaxBaseFeePerGas = MaxBaseFeePerGas; type DefaultBaseFeePerGas = DefaultBaseDFeePerGas; type FeeMultiplier = MultiplierProviderMock; type NativePriceOracle = NativePriceOracleMock; diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index 53344ab60..10457b067 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -182,11 +182,15 @@ impl pallet_evm_accounts::Config for crate::Runtime { parameter_types! { pub const DefaultBaseFeePerGas: u128 = DEFAULT_BASE_FEE_PER_GAS; + pub const MinBaseFeePerGas: u128 = DEFAULT_BASE_FEE_PER_GAS.saturating_div(10); + pub const MaxBaseFeePerGas: u128 = 14415000000; //To reach 10 dollar per omnipool trade } impl pallet_dynamic_evm_fee::Config for crate::Runtime { type AssetId = AssetId; type DefaultBaseFeePerGas = DefaultBaseFeePerGas; + type MinBaseFeePerGas = MinBaseFeePerGas; + type MaxBaseFeePerGas = MaxBaseFeePerGas; type FeeMultiplier = TransactionPaymentMultiplier; type NativePriceOracle = AssetFeeOraclePriceProvider< NativeAssetId, From 4bd8fa89d4007409d5a9bf7d8773174171b33f60 Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 23 Feb 2024 16:33:08 +0100 Subject: [PATCH 56/64] make benchmark compile --- runtime/hydradx/src/benchmarking/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/hydradx/src/benchmarking/mod.rs b/runtime/hydradx/src/benchmarking/mod.rs index 535232b6f..946955e43 100644 --- a/runtime/hydradx/src/benchmarking/mod.rs +++ b/runtime/hydradx/src/benchmarking/mod.rs @@ -24,8 +24,8 @@ use sp_std::vec::Vec; pub const BSX: Balance = primitives::constants::currency::UNITS; use frame_support::storage::with_transaction; +use hydradx_traits::Mutate; use sp_runtime::TransactionOutcome; - pub fn register_asset(name: Vec, deposit: Balance) -> Result { let n = name.try_into().map_err(|_| ())?; with_transaction(|| { @@ -61,7 +61,7 @@ pub fn register_external_asset(name: Vec) -> Result { } pub fn set_location(asset_id: AssetId, location: AssetLocation) -> Result<(), ()> { - AssetRegistry::set_location(RawOrigin::Root.into(), asset_id, location).map_err(|_| ()) + AssetRegistry::set_location(asset_id, location).map_err(|_| ()) } pub fn add_as_accepted_currency(asset_id: AssetId, price: Price) -> Result<(), ()> { From 59598ed59cae55643f53c4303feb50601202337a Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 23 Feb 2024 16:42:04 +0100 Subject: [PATCH 57/64] used checked for rational calc --- pallets/dynamic-evm-fee/src/lib.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index db1a5780c..f3138becb 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -60,11 +60,8 @@ use frame_system::pallet_prelude::BlockNumberFor; use hydra_dx_math::ema::EmaPrice; use hydradx_traits::NativePriceOracle; use sp_core::U256; -use sp_runtime::traits::CheckedDiv; use sp_runtime::FixedPointNumber; use sp_runtime::FixedU128; -use sp_runtime::Permill; -use sp_runtime::Saturating; pub const ETH_HDX_REFERENCE_PRICE: FixedU128 = FixedU128::from_inner(8945857934143137845); //Current onchain ETH price on at block #4,534,103 @@ -140,9 +137,15 @@ pub mod pallet { log::warn!(target: "runtime::dynamic-evm-fee", "Could not get ETH-HDX price from oracle"); return; }; - let eth_hdx_price = FixedU128::from_rational(eth_hdx_price.n, eth_hdx_price.d); - let price_diff = - FixedU128::from_rational(eth_hdx_price.into_inner(), ETH_HDX_REFERENCE_PRICE.into_inner()); + let Some(eth_hdx_price) = FixedU128::checked_from_rational(eth_hdx_price.n, eth_hdx_price.d) else { + log::warn!(target: "runtime::dynamic-evm-fee", "Could not get rational of eth-hdx price, n: {}, d: {}", eth_hdx_price.n, eth_hdx_price.d); + return; + }; + + let Some(price_diff) = FixedU128::checked_from_rational(eth_hdx_price.into_inner(), ETH_HDX_REFERENCE_PRICE.into_inner()) else { + log::warn!(target: "runtime::dynamic-evm-fee", "Could not get rational of eth-hdx price, current price: {}, reference price: {}", eth_hdx_price, ETH_HDX_REFERENCE_PRICE); + return; + }; new_base_fee_per_gas = price_diff.saturating_mul_int(new_base_fee_per_gas); From 37f585ebee004a3d881ee62fe8741dc9a670198e Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 23 Feb 2024 16:42:16 +0100 Subject: [PATCH 58/64] fix compilation --- .../src/tests/on_initialize.rs | 13 ++++------ .../src/benchmarking/dynamic_evm_fee.rs | 24 ++++++++++++++++--- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs index 456eeb3d7..1a4059c2f 100644 --- a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs +++ b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs @@ -4,9 +4,6 @@ use frame_support::traits::OnInitialize; use hydra_dx_math::types::Ratio; use pallet_transaction_payment::Multiplier; use sp_core::U256; -use sp_runtime::FixedPointNumber; -use sp_runtime::FixedU128; -use sp_runtime::Saturating; #[test] fn should_return_default_base_fee_when_min_multiplier() { @@ -41,7 +38,7 @@ fn should_increase_evm_fee_when_hdx_pumping_10percent_against_eth() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(16549500)); + assert_eq!(new_base_fee, U256::from(16549499)); }); } @@ -57,14 +54,14 @@ fn should_not_change_when_price_pumps_then_remains_same_in_consquent_block() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(16549500)); + assert_eq!(new_base_fee, U256::from(16549499)); //Act DynamicEvmFee::on_initialize(2); //Assert let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(16549500)); + assert_eq!(new_base_fee, U256::from(16549499)); }); } @@ -78,7 +75,7 @@ fn should_increase_evm_fee_when_hdx_pumping_1percent_against_eth() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(15195450)); + assert_eq!(new_base_fee, U256::from(15195449)); }); } @@ -92,7 +89,7 @@ fn should_decrease_evm_fee_when_hdx_dumping_10percent_against_eth() { DynamicEvmFee::on_initialize(1); let new_base_fee = DynamicEvmFee::base_evm_fee(); - assert_eq!(new_base_fee, U256::from(13540500)); + assert_eq!(new_base_fee, U256::from(13540499)); }); } diff --git a/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs b/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs index 0c31ecb58..e0a16db54 100644 --- a/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs +++ b/runtime/hydradx/src/benchmarking/dynamic_evm_fee.rs @@ -111,11 +111,29 @@ mod tests { pallet_asset_registry::GenesisConfig:: { registered_assets: vec![ - (b"LRNA".to_vec(), 1_000u128, Some(1)), - (b"DAI".to_vec(), 1_000u128, Some(2)), + ( + Some(1), + Some(b"LRNA".to_vec().try_into().unwrap()), + 1_000u128, + None, + None, + None, + true, + ), + ( + Some(2), + Some(b"DAI".to_vec().try_into().unwrap()), + 1_000u128, + None, + None, + None, + true, + ), ], - native_asset_name: b"HDX".to_vec(), + native_asset_name: b"HDX".to_vec().try_into().unwrap(), native_existential_deposit: NativeExistentialDeposit::get(), + native_decimals: 12, + native_symbol: b"HDX".to_vec().try_into().unwrap(), } .assimilate_storage(&mut t) .unwrap(); From 153924c60be59695752fd1eb114ccf8d9ce8a97b Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 23 Feb 2024 16:47:29 +0100 Subject: [PATCH 59/64] rebenchmark pallet --- runtime/hydradx/src/weights/dynamic_evm_fee.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/runtime/hydradx/src/weights/dynamic_evm_fee.rs b/runtime/hydradx/src/weights/dynamic_evm_fee.rs index 776101ca3..dad1ab154 100644 --- a/runtime/hydradx/src/weights/dynamic_evm_fee.rs +++ b/runtime/hydradx/src/weights/dynamic_evm_fee.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_dynamic_evm_fee` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-02-06, STEPS: `10`, REPEAT: `30`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-23, STEPS: `10`, REPEAT: `30`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `dmoka-msi-pc`, CPU: `AMD Ryzen 9 5900X 12-Core Processor` +//! HOSTNAME: `bench-bot`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 // Executed Command: @@ -34,7 +34,7 @@ // --heap-pages=4096 // --template=.maintain/pallet-weight-template-no-back.hbs // --pallet=pallet-dynamic-evm-fee -// --output=dynamic-evm-fee.rs +// --output=dyn.rs // --extrinsic=* #![cfg_attr(rustfmt, rustfmt_skip)] @@ -66,8 +66,8 @@ impl pallet_dynamic_evm_fee::WeightInfo for HydraWeight // Proof Size summary in bytes: // Measured: `2709` // Estimated: `11598` - // Minimum execution time: 68_199_000 picoseconds. - Weight::from_parts(71_750_000, 11598) + // Minimum execution time: 73_589_000 picoseconds. + Weight::from_parts(74_453_000, 11598) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(1)) } From cc7af89f232cb0eec76d60728cd753ef446d8430 Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 23 Feb 2024 16:51:28 +0100 Subject: [PATCH 60/64] fix doc --- pallets/dynamic-evm-fee/README.md | 4 ++-- pallets/dynamic-evm-fee/src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pallets/dynamic-evm-fee/README.md b/pallets/dynamic-evm-fee/README.md index 20596d42d..9b520080a 100644 --- a/pallets/dynamic-evm-fee/README.md +++ b/pallets/dynamic-evm-fee/README.md @@ -21,8 +21,8 @@ BaseFeePerGas = DefaultBaseFeePerGas + (DefaultBaseFeePerGas * Multiplier * 3) ### Fee Adjustment Based on ETH-HDX Price Fluctuations The transaction fee is also adjusted in accordance with in ETH-HDX oracle price change: -- When HDX increases in value against ETH, the fee is reduced accordingly. -- When HDX decreases in value against ETH, the fee is increased accordingly. +- When HDX increases in value against ETH, the evm fee is increased accordingly. +- When HDX decreases in value against ETH, the evm fee is decreased accordingly. This dual-criteria approach ensures that transaction fees remain fair and reflective of both market conditions and network demand. diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index f3138becb..36c74e09b 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -38,8 +38,8 @@ //! ### Fee Adjustment Based on ETH-HDX Price Fluctuations //! //! The transaction fee is also adjusted in accordance with in ETH-HDX oracle price change: -//! - When HDX increases in value against ETH, the fee is reduced accordingly. -//! - When HDX decreases in value against ETH, the fee is increased accordingly. +//! - When HDX increases in value against ETH, the evm fee is increased accordingly. +//! - When HDX decreases in value against ETH, the evm fee is decreased accordingly. //! //! This dual-criteria approach ensures that transaction fees remain fair and reflective of both market conditions and network demand. From d3bc8c504fc99158f0d293d48888e740b9f4b689 Mon Sep 17 00:00:00 2001 From: dmoka Date: Fri, 23 Feb 2024 16:57:03 +0100 Subject: [PATCH 61/64] make clippy happy --- pallets/dynamic-evm-fee/src/tests/on_initialize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs index 1a4059c2f..81e4376b4 100644 --- a/pallets/dynamic-evm-fee/src/tests/on_initialize.rs +++ b/pallets/dynamic-evm-fee/src/tests/on_initialize.rs @@ -97,7 +97,7 @@ fn should_decrease_evm_fee_when_hdx_dumping_10percent_against_eth() { fn evm_fee_should_go_to_minimum_when_hdx_dumps_a_alot() { ExtBuilder::default().build().execute_with(|| { set_oracle_price(Ratio::new( - DEFAULT_ETH_HDX_ORACLE_PRICE.n * 1 / 100, + DEFAULT_ETH_HDX_ORACLE_PRICE.n / 100, DEFAULT_ETH_HDX_ORACLE_PRICE.d, )); DynamicEvmFee::on_initialize(1); From 07c5fefcc3e313f7035594cbbe4f96f0a41f861b Mon Sep 17 00:00:00 2001 From: dmoka Date: Mon, 26 Feb 2024 08:37:05 +0100 Subject: [PATCH 62/64] fix namings --- pallets/dynamic-evm-fee/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index 36c74e09b..e73de3887 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -161,7 +161,7 @@ pub mod pallet { fn integrity_test() { assert!( T::MinBaseFeePerGas::get() < T::MaxBaseFeePerGas::get(), - "DefaultBaseFeePerGas should be less than MAX_BASE_FEE_PER_GAS, otherwise it fails when we clamp when we bound the value" + "MinBaseFeePerGas should be less than MaxBaseFeePerGas, otherwise it fails when we clamp when we bound the value" ); } } From bcd9425572e38ac5e0051d2e0da150031ad6620f Mon Sep 17 00:00:00 2001 From: dmoka Date: Mon, 26 Feb 2024 08:38:10 +0100 Subject: [PATCH 63/64] adjust error message --- pallets/dynamic-evm-fee/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/dynamic-evm-fee/src/lib.rs b/pallets/dynamic-evm-fee/src/lib.rs index e73de3887..489a89fb8 100644 --- a/pallets/dynamic-evm-fee/src/lib.rs +++ b/pallets/dynamic-evm-fee/src/lib.rs @@ -161,7 +161,7 @@ pub mod pallet { fn integrity_test() { assert!( T::MinBaseFeePerGas::get() < T::MaxBaseFeePerGas::get(), - "MinBaseFeePerGas should be less than MaxBaseFeePerGas, otherwise it fails when we clamp when we bound the value" + "MinBaseFeePerGas should be less than MaxBaseFeePerGas, otherwise it fails when we clamp for bounding the base fee per gas." ); } } From a87fc751518f482044d049c889915a5f94d8f8d1 Mon Sep 17 00:00:00 2001 From: dmoka Date: Mon, 26 Feb 2024 09:00:33 +0100 Subject: [PATCH 64/64] bump runtime version --- Cargo.lock | 2 +- runtime/hydradx/Cargo.toml | 2 +- runtime/hydradx/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbed517e9..08ea0b48e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4621,7 +4621,7 @@ dependencies = [ [[package]] name = "hydradx-runtime" -version = "215.0.0" +version = "216.0.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index b1728ee43..5f91aa3d8 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-runtime" -version = "215.0.0" +version = "216.0.0" authors = ["GalacticCouncil"] edition = "2021" license = "Apache 2.0" diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 73b8fe244..f27f0473f 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -107,7 +107,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("hydradx"), impl_name: create_runtime_str!("hydradx"), authoring_version: 1, - spec_version: 215, + spec_version: 216, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1,