diff --git a/Cargo.lock b/Cargo.lock index 7b108fd13..df0c8cf8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4571,7 +4571,7 @@ dependencies = [ [[package]] name = "hydradx-adapters" -version = "1.2.4" +version = "1.2.5" dependencies = [ "cumulus-pallet-parachain-system", "cumulus-primitives-core", @@ -4621,7 +4621,7 @@ dependencies = [ [[package]] name = "hydradx-runtime" -version = "223.0.0" +version = "224.0.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -4747,7 +4747,7 @@ dependencies = [ [[package]] name = "hydradx-traits" -version = "3.1.0" +version = "3.1.1" dependencies = [ "frame-support", "impl-trait-for-tuples", @@ -7403,7 +7403,7 @@ dependencies = [ [[package]] name = "pallet-dca" -version = "1.4.0" +version = "1.4.1" dependencies = [ "cumulus-pallet-parachain-system", "cumulus-primitives-core", @@ -8321,7 +8321,7 @@ dependencies = [ [[package]] name = "pallet-route-executor" -version = "2.1.0" +version = "2.2.0" dependencies = [ "frame-benchmarking", "frame-support", @@ -11365,7 +11365,7 @@ dependencies = [ [[package]] name = "runtime-integration-tests" -version = "1.19.9" +version = "1.19.10" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 4e6999ae0..7684cc98a 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "runtime-integration-tests" -version = "1.19.9" +version = "1.19.10" description = "Integration tests" authors = ["GalacticCouncil"] edition = "2021" diff --git a/integration-tests/src/router.rs b/integration-tests/src/router.rs index 9e26ab7ee..4fc60d5a5 100644 --- a/integration-tests/src/router.rs +++ b/integration-tests/src/router.rs @@ -53,6 +53,53 @@ fn router_weights_should_be_non_zero() { mod router_different_pools_tests { use super::*; + #[test] + fn route_should_fail_when_route_is_not_consistent() { + TestNet::reset(); + + Hydra::execute_with(|| { + //Arrange + init_omnipool(); + create_xyk_pool_with_amounts(DAI, 1000000 * UNITS, DOT, 1000000 * UNITS); + create_xyk_pool_with_amounts(ETH, 1000000 * UNITS, DOT, 1000000 * UNITS); + + assert_ok!(Currencies::update_balance( + hydradx_runtime::RuntimeOrigin::root(), + BOB.into(), + ETH, + 300000000 * UNITS as i128, + )); + + let amount_to_sell = UNITS; + let limit = 0; + let trades = vec![ + Trade { + pool: PoolType::Omnipool, + asset_in: HDX, + asset_out: DAI, + }, + Trade { + pool: PoolType::XYK, + asset_in: ETH, + asset_out: DOT, + }, + ]; + + //Act + assert_noop!( + Router::sell( + RuntimeOrigin::signed(BOB.into()), + HDX, + DOT, + amount_to_sell, + limit, + trades + ), + pallet_route_executor::Error::::InvalidRoute + ); + }); + } + #[test] fn sell_should_work_when_route_contains_trades_with_different_pools() { TestNet::reset(); @@ -2847,7 +2894,7 @@ mod set_route { } #[test] - fn set_route_should_not_work_when_no_existing_and_reversed_route_is_not_valid_for_trade() { + fn set_route_should_not_work_when_new_route_is_invalid() { TestNet::reset(); Hydra::execute_with(|| { @@ -2913,16 +2960,22 @@ mod set_route { }, ]; + assert_ok!(hydradx_runtime::Omnipool::set_asset_tradable_state( + hydradx_runtime::RuntimeOrigin::root(), + DOT, + Tradability::FROZEN + )); + //Act and assert assert_noop!( Router::set_route(hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), asset_pair, route2), - pallet_route_executor::Error::::InvalidRoute + pallet_omnipool::Error::::NotAllowed ); }); } #[test] - fn set_route_should_not_work_when_reversed_route_is_not_valid_due_to_maxout_ratio() { + fn set_route_should_work_when_stored_route_is_broken_due_to_frozen_asset() { TestNet::reset(); Hydra::execute_with(|| { @@ -2933,7 +2986,7 @@ mod set_route { hydradx_runtime::RuntimeOrigin::root(), Omnipool::protocol_account(), DOT, - 3000 * UNITS as i128, + 1000000000000 * UNITS as i128, )); assert_ok!(hydradx_runtime::Omnipool::add_token( @@ -2945,20 +2998,12 @@ mod set_route { )); create_xyk_pool_with_amounts(HDX, 1000000 * UNITS, DOT, 1000000 * UNITS); - create_xyk_pool_with_amounts(DOT, 1000000 * UNITS, BTC, 1000000 * UNITS); - - create_xyk_pool_with_amounts(HDX, 1000000 * UNITS, DAI, 1000000 * UNITS); - create_xyk_pool_with_amounts(DAI, 1000000 * UNITS, DOT, 1000000 * UNITS); + create_xyk_pool_with_amounts(DOT, 50000 * UNITS, BTC, 4000000 * UNITS); let route1 = vec![ Trade { - pool: PoolType::XYK, + pool: PoolType::Omnipool, asset_in: HDX, - asset_out: DAI, - }, - Trade { - pool: PoolType::XYK, - asset_in: DAI, asset_out: DOT, }, Trade { @@ -2976,9 +3021,15 @@ mod set_route { route1 )); + assert_ok!(Omnipool::set_asset_tradable_state( + RuntimeOrigin::root(), + DOT, + Tradability::FROZEN + )); + let route2 = vec![ Trade { - pool: PoolType::Omnipool, + pool: PoolType::XYK, asset_in: HDX, asset_out: DOT, }, @@ -2989,16 +3040,43 @@ mod set_route { }, ]; + //Act and assert + assert_ok!(Router::set_route( + hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), + asset_pair, + route2 + ),); + }); + } + + #[test] + fn set_route_should_fail_when_no_prestored_but_inverse_route_is_invalid() { + TestNet::reset(); + + Hydra::execute_with(|| { + //Arrange + init_omnipool(); + + create_xyk_pool_with_amounts(HDX, 100 * UNITS, BTC, 100000000 * UNITS); + + let asset_pair = Pair::new(HDX, BTC); + + let route2 = vec![Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: BTC, + }]; + //Act and assert assert_noop!( Router::set_route(hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), asset_pair, route2), - pallet_route_executor::Error::::InvalidRoute + sp_runtime::TokenError::BelowMinimum ); }); } #[test] - fn set_route_should_work_when_stored_route_is_broken_due_to_frozen_asset() { + fn set_route_should_pass_when_normal_is_broken_but_revalidated_with_amount_from_inverse() { TestNet::reset(); Hydra::execute_with(|| { @@ -3009,7 +3087,7 @@ mod set_route { hydradx_runtime::RuntimeOrigin::root(), Omnipool::protocol_account(), DOT, - 1000000000000 * UNITS as i128, + 100000000 * UNITS as i128, )); assert_ok!(hydradx_runtime::Omnipool::add_token( @@ -3020,39 +3098,13 @@ mod set_route { AccountId::from(BOB), )); - create_xyk_pool_with_amounts(HDX, 1000000 * UNITS, DOT, 1000000 * UNITS); - create_xyk_pool_with_amounts(DOT, 50000 * UNITS, BTC, 4000000 * UNITS); - - let route1 = vec![ - Trade { - pool: PoolType::Omnipool, - asset_in: HDX, - asset_out: DOT, - }, - Trade { - pool: PoolType::XYK, - asset_in: DOT, - asset_out: BTC, - }, - ]; + create_xyk_pool_with_amounts(DOT, 1 * UNITS, BTC, 1 * UNITS); let asset_pair = Pair::new(HDX, BTC); - assert_ok!(Router::set_route( - hydradx_runtime::RuntimeOrigin::signed(ALICE.into()), - asset_pair, - route1 - )); - - assert_ok!(Omnipool::set_asset_tradable_state( - RuntimeOrigin::root(), - DOT, - Tradability::FROZEN - )); - let route2 = vec![ Trade { - pool: PoolType::XYK, + pool: PoolType::Omnipool, asset_in: HDX, asset_out: DOT, }, diff --git a/pallets/dca/Cargo.toml b/pallets/dca/Cargo.toml index 6a379fcc5..c921e6f6e 100644 --- a/pallets/dca/Cargo.toml +++ b/pallets/dca/Cargo.toml @@ -1,6 +1,6 @@ [package] name = 'pallet-dca' -version = "1.4.0" +version = "1.4.1" description = 'A pallet to manage DCA scheduling' authors = ['GalacticCouncil'] edition = '2021' diff --git a/pallets/dca/src/tests/mock.rs b/pallets/dca/src/tests/mock.rs index 955bdb971..d24f1e671 100644 --- a/pallets/dca/src/tests/mock.rs +++ b/pallets/dca/src/tests/mock.rs @@ -397,6 +397,7 @@ impl pallet_route_executor::Config for Test { type InspectRegistry = MockedAssetRegistry; type DefaultRoutePoolType = DefaultRoutePoolType; type WeightInfo = (); + type TechnicalOrigin = EnsureRoot; } type OriginForRuntime = OriginFor; diff --git a/pallets/route-executor/Cargo.toml b/pallets/route-executor/Cargo.toml index 28e17086f..db6487946 100644 --- a/pallets/route-executor/Cargo.toml +++ b/pallets/route-executor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = 'pallet-route-executor' -version = '2.1.0' +version = '2.2.0' description = 'A pallet to execute a route containing a sequence of trades' authors = ['GalacticCouncil'] edition = '2021' diff --git a/pallets/route-executor/README.md b/pallets/route-executor/README.md index de3a6339b..09ad44f81 100644 --- a/pallets/route-executor/README.md +++ b/pallets/route-executor/README.md @@ -18,6 +18,9 @@ If the route is set successfully, then the fee is payed back. If the route setting fails, it emits event `RouteUpdateIsNotSuccessful` +### Force insert route +The route can be force inserted for any asset pair by technical origin without involving any validation. + ### Providing routes This pallet is also responsible for providing the best routes for asset pairs. diff --git a/pallets/route-executor/src/lib.rs b/pallets/route-executor/src/lib.rs index 2a39f44e2..85a65edeb 100644 --- a/pallets/route-executor/src/lib.rs +++ b/pallets/route-executor/src/lib.rs @@ -50,8 +50,6 @@ pub use pallet::*; pub const MAX_NUMBER_OF_TRADES: u32 = 5; -//TODO: rebenchmark on reference machine - #[frame_support::pallet] pub mod pallet { use super::*; @@ -107,6 +105,9 @@ pub mod pallet { /// Pool type used in the default route type DefaultRoutePoolType: Get>; + /// Origin able to set route without validation + type TechnicalOrigin: EnsureOrigin; + /// Weight information for the extrinsics. type WeightInfo: AmmTradeWeights>; } @@ -375,17 +376,29 @@ pub mod pallet { match Self::validate_route(&existing_route) { Ok((reference_amount_in, reference_amount_in_for_inverse)) => { - let inverse_new_route = inverse_route(new_route.to_vec()); - let inverse_existing_route = inverse_route(existing_route.to_vec()); + let new_route_validation = Self::validate_sell(new_route.clone(), reference_amount_in); - Self::validate_sell(new_route.clone(), reference_amount_in)?; - Self::validate_sell(inverse_new_route.clone(), reference_amount_in_for_inverse)?; + let inverse_new_route = inverse_route(new_route.to_vec()); + let inverse_new_route_validation = + Self::validate_sell(inverse_new_route.clone(), reference_amount_in_for_inverse); + + match (new_route_validation, inverse_new_route_validation) { + (Ok(_), Ok(_)) => (), + (Err(_), Ok(amount_out)) => { + Self::validate_sell(new_route.to_vec(), amount_out).map(|_| ())?; + } + (Ok(amount_out), Err(_)) => { + Self::validate_sell(inverse_new_route.clone(), amount_out).map(|_| ())?; + } + (Err(err), Err(_)) => return Err(err.into()), + } let amount_out_for_existing_route = Self::calculate_expected_amount_out(&existing_route, reference_amount_in)?; let amount_out_for_new_route = Self::calculate_expected_amount_out(&new_route, reference_amount_in)?; + let inverse_existing_route = inverse_route(existing_route.to_vec()); let amount_out_for_existing_inversed_route = Self::calculate_expected_amount_out(&inverse_existing_route, reference_amount_in_for_inverse)?; let amount_out_for_new_inversed_route = @@ -406,6 +419,38 @@ pub mod pallet { Err(Error::::RouteUpdateIsNotSuccessful.into()) } + + /// Force inserts the on-chain route for a given asset pair, so there is no any validation for the route + /// + /// Can only be called by technical origin + /// + /// The route is stored in an ordered manner, based on the oder of the ids in the asset pair. + /// + /// If the route is set successfully, then the fee is payed back. + /// + /// - `origin`: The origin of the route setter + /// - `asset_pair`: The identifier of the asset-pair for which the route is set + /// - `new_route`: Series of [`Trade`] to be executed. A [`Trade`] specifies the asset pair (`asset_in`, `asset_out`) and the AMM (`pool`) in which the trade is executed. + /// + /// Emits `RouteUpdated` when successful. + /// + #[pallet::call_index(3)] + #[pallet::weight(T::WeightInfo::force_insert_route_weight())] + #[transactional] + pub fn force_insert_route( + origin: OriginFor, + mut asset_pair: AssetPair, + mut new_route: Vec>, + ) -> DispatchResultWithPostInfo { + T::TechnicalOrigin::ensure_origin(origin)?; + + if !asset_pair.is_ordered() { + asset_pair = asset_pair.ordered_pair(); + new_route = inverse_route(new_route) + } + + Self::insert_route(asset_pair, new_route) + } } } @@ -437,6 +482,13 @@ impl Pallet { Error::::InvalidRoute ); + for i in 0..route.len().saturating_sub(1) { + let asset_out = route.get(i).ok_or(Error::::InvalidRoute)?.asset_out; + let next_trade_asset_in = route.get(i.saturating_add(1)).ok_or(Error::::InvalidRoute)?.asset_in; + + ensure!(asset_out == next_trade_asset_in, Error::::InvalidRoute) + } + Ok(()) } @@ -513,13 +565,22 @@ impl Pallet { fn validate_route(route: &[Trade]) -> Result<(T::Balance, T::Balance), DispatchError> { let reference_amount_in = Self::calculate_reference_amount_in(route)?; - Self::validate_sell(route.to_vec(), reference_amount_in)?; + let route_validation = Self::validate_sell(route.to_vec(), reference_amount_in); let inverse_route = inverse_route(route.to_vec()); let reference_amount_in_for_inverse_route = Self::calculate_reference_amount_in(&inverse_route)?; - Self::validate_sell(inverse_route, reference_amount_in_for_inverse_route)?; - - Ok((reference_amount_in, reference_amount_in_for_inverse_route)) + let inverse_route_validation = + Self::validate_sell(inverse_route.clone(), reference_amount_in_for_inverse_route); + + match (route_validation, inverse_route_validation) { + (Ok(_), Ok(_)) => Ok((reference_amount_in, reference_amount_in_for_inverse_route)), + (Err(_), Ok(amount_out)) => Self::validate_sell(route.clone().to_vec(), amount_out) + .map(|_| (amount_out, reference_amount_in_for_inverse_route)), + (Ok(amount_out), Err(_)) => { + Self::validate_sell(inverse_route, amount_out).map(|_| (reference_amount_in, amount_out)) + } + (Err(err), Err(_)) => Err(err), + } } fn calculate_reference_amount_in(route: &[Trade]) -> Result { @@ -546,19 +607,23 @@ impl Pallet { Ok(one_percent_asset_in_liquidity) } - fn validate_sell(route: Vec>, amount_in: T::Balance) -> DispatchResult { + fn validate_sell(route: Vec>, amount_in: T::Balance) -> Result { let asset_in = route.first().ok_or(Error::::InvalidRoute)?.asset_in; let asset_out = route.last().ok_or(Error::::InvalidRoute)?.asset_out; - with_transaction(|| { + with_transaction::(|| { let origin: OriginFor = Origin::::Signed(Self::router_account()).into(); + let Ok(who) = ensure_signed(origin.clone()) else { + return TransactionOutcome::Rollback(Err(Error::::InvalidRoute.into())) + }; let _ = T::Currency::mint_into(asset_in, &Self::router_account(), amount_in); let sell_result = Self::sell(origin, asset_in, asset_out, amount_in, u128::MIN.into(), route.clone()); + let amount_out = + T::Currency::reducible_balance(asset_out, &who, Preservation::Expendable, Fortitude::Polite); - TransactionOutcome::Rollback(sell_result) + TransactionOutcome::Rollback(sell_result.map(|_| amount_out)) }) - .map_err(|_| Error::::InvalidRoute.into()) } fn calculate_expected_amount_out( @@ -679,6 +744,14 @@ impl RouterT DispatchResultWithPostInfo { Pallet::::set_route(origin, asset_pair, route) } + + fn force_insert_route( + origin: T::RuntimeOrigin, + asset_pair: AssetPair, + route: Vec>, + ) -> DispatchResultWithPostInfo { + Pallet::::force_insert_route(origin, asset_pair, route) + } } pub struct DummyRouter(PhantomData); @@ -734,6 +807,14 @@ impl RouterT DispatchResultWithPostInfo { Ok(Pays::Yes.into()) } + + fn force_insert_route( + _origin: T::RuntimeOrigin, + _asset_pair: AssetPair, + _route: Vec>, + ) -> DispatchResultWithPostInfo { + Ok(Pays::Yes.into()) + } } #[macro_export] diff --git a/pallets/route-executor/src/tests/force_insert_route.rs b/pallets/route-executor/src/tests/force_insert_route.rs new file mode 100644 index 000000000..4dbd209c2 --- /dev/null +++ b/pallets/route-executor/src/tests/force_insert_route.rs @@ -0,0 +1,110 @@ +// This file is part of HydraDX. + +// 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 crate::tests::mock::*; +use crate::{Error, Trade}; +use frame_support::pallet_prelude::*; +use frame_support::{assert_noop, assert_ok}; +use hydradx_traits::router::{AssetPair, PoolType}; +use pretty_assertions::assert_eq; +use sp_runtime::DispatchError::BadOrigin; + +#[test] +fn force_insert_should_not_work_when_called_with_non_technical_origin() { + ExtBuilder::default().build().execute_with(|| { + //Arrange + let asset_pair = AssetPair::new(HDX, AUSD); + let route = vec![Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: AUSD, + }]; + + //Act + assert_noop!( + Router::force_insert_route(RuntimeOrigin::signed(ALICE), asset_pair, route), + BadOrigin + ); + }); +} + +#[test] +fn force_insert_should_work_when_called_with_technical_origin() { + ExtBuilder::default().build().execute_with(|| { + //Arrange + let asset_pair = AssetPair::new(HDX, AUSD); + let route = vec![Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: AUSD, + }]; + + //Act + assert_ok!( + Router::force_insert_route(RuntimeOrigin::root(), asset_pair, route), + Pays::No.into() + ); + }); +} + +#[test] +fn force_insert_should_fail_when_called_with_too_big_route() { + ExtBuilder::default().build().execute_with(|| { + //Arrange + let asset_pair = AssetPair::new(HDX, AUSD); + let route = vec![ + Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: AUSD, + }, + Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: AUSD, + }, + Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: AUSD, + }, + Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: AUSD, + }, + Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: AUSD, + }, + Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: AUSD, + }, + ]; + + //Act + assert_noop!( + Router::force_insert_route(RuntimeOrigin::root(), asset_pair, route), + Error::::MaxTradesExceeded + ); + }); +} + +//TODO: add test that it can add insuffucient asset diff --git a/pallets/route-executor/src/tests/mock.rs b/pallets/route-executor/src/tests/mock.rs index 2db151dbb..b6374b48f 100644 --- a/pallets/route-executor/src/tests/mock.rs +++ b/pallets/route-executor/src/tests/mock.rs @@ -21,6 +21,7 @@ use frame_support::{ parameter_types, traits::{Everything, Nothing}, }; +use frame_system::EnsureRoot; use frame_system::{ensure_signed, pallet_prelude::OriginFor}; use hydradx_traits::router::{ExecutorError, PoolType, TradeExecution}; use orml_traits::parameter_type_with_key; @@ -148,6 +149,7 @@ impl Config for Test { type InspectRegistry = MockedAssetRegistry; type AMM = Pools; type DefaultRoutePoolType = DefaultRoutePoolType; + type TechnicalOrigin = EnsureRoot; type WeightInfo = (); } diff --git a/pallets/route-executor/src/tests/mod.rs b/pallets/route-executor/src/tests/mod.rs index 145c5b2ba..922294662 100644 --- a/pallets/route-executor/src/tests/mod.rs +++ b/pallets/route-executor/src/tests/mod.rs @@ -1,4 +1,5 @@ pub mod buy; +pub mod force_insert_route; pub mod mock; pub mod sell; pub mod set_route; diff --git a/pallets/route-executor/src/tests/sell.rs b/pallets/route-executor/src/tests/sell.rs index 31ac2142b..21399b2ab 100644 --- a/pallets/route-executor/src/tests/sell.rs +++ b/pallets/route-executor/src/tests/sell.rs @@ -521,3 +521,34 @@ fn sell_should_fail_when_assets_dont_correspond_to_route() { ); }); } + +#[test] +fn sell_should_fail_when_intermediare_assets_are_inconsistent() { + ExtBuilder::default().build().execute_with(|| { + //Arrange + let amount_to_sell = 10; + let limit = 5; + let trade1 = Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: AUSD, + }; + let trade2 = Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: MOVR, + }; + let trade3 = Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: KSM, + }; + let trades = vec![trade1, trade2, trade3]; + + //Act + assert_noop!( + Router::sell(RuntimeOrigin::signed(ALICE), HDX, KSM, amount_to_sell, limit, trades), + Error::::InvalidRoute + ); + }); +} diff --git a/pallets/route-executor/src/weights.rs b/pallets/route-executor/src/weights.rs index 42ed0f1c4..be4375720 100644 --- a/pallets/route-executor/src/weights.rs +++ b/pallets/route-executor/src/weights.rs @@ -15,10 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. + //! Autogenerated weights for `pallet_route_executor` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-12, STEPS: `5`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-18, STEPS: `10`, REPEAT: `30`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bench-bot`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -27,38 +28,34 @@ // target/release/hydradx // benchmark // pallet -// --pallet=pallet-route-executor +// --chain=dev +// --steps=10 +// --repeat=30 // --wasm-execution=compiled // --heap-pages=4096 -// --chain=dev +// --template=.maintain/pallet-weight-template.hbs +// --pallet=pallet_route-executor +// --output=re2.rs // --extrinsic=* -// --steps=5 -// --repeat=20 -// --output -// ./weights-1.1.0/route_executor.rs -// --template -// .maintain/pallet-weight-template-no-back.hbs +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -#![allow(clippy::unnecessary_cast)] +#![allow(missing_docs)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; -use sp_std::marker::PhantomData; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; -/// Weight functions needed for pallet_route_executor. +/// Weight functions needed for `pallet_route_executor`. pub trait WeightInfo { - fn calculate_and_execute_sell_in_lbp(c: u32) -> Weight; - fn calculate_and_execute_buy_in_lbp(c: u32, b: u32) -> Weight; + fn calculate_and_execute_sell_in_lbp(c: u32, ) -> Weight; + fn calculate_and_execute_buy_in_lbp(c: u32, b: u32, ) -> Weight; fn set_route_for_xyk() -> Weight; + fn force_insert_route() -> Weight; } -/// Weights for pallet_route_executor using the hydraDX node and recommended hardware. +/// Weights for `pallet_route_executor` using the HydraDX node and recommended hardware. pub struct HydraWeight(PhantomData); - impl WeightInfo for HydraWeight { /// Storage: `LBP::PoolData` (r:1 w:0) /// Proof: `LBP::PoolData` (`max_values`: None, `max_size`: Some(163), added: 2638, mode: `MaxEncodedLen`) @@ -68,18 +65,22 @@ impl WeightInfo for HydraWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Tokens::Locks` (r:1 w:1) /// Proof: `Tokens::Locks` (`max_values`: None, `max_size`: Some(1261), added: 3736, mode: `MaxEncodedLen`) + /// Storage: `Duster::AccountBlacklist` (r:2 w:0) + /// Proof: `Duster::AccountBlacklist` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::BannedAssets` (r:2 w:0) + /// Proof: `AssetRegistry::BannedAssets` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) /// Storage: `AssetRegistry::Assets` (r:2 w:0) - /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(87), added: 2562, mode: `MaxEncodedLen`) + /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(125), added: 2600, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1]`. - fn calculate_and_execute_sell_in_lbp(c: u32) -> Weight { + fn calculate_and_execute_sell_in_lbp(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3016` + // Measured: `3436` // Estimated: `13905` - // Minimum execution time: 316_311_000 picoseconds. - Weight::from_parts(318_353_450, 13905) - // Standard Error: 164_994 - .saturating_add(Weight::from_parts(50_546_750, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(12_u64)) + // Minimum execution time: 342_467_000 picoseconds. + Weight::from_parts(346_028_529, 13905) + // Standard Error: 185_098 + .saturating_add(Weight::from_parts(50_586_970, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(16_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `LBP::PoolData` (r:1 w:0) @@ -90,55 +91,73 @@ impl WeightInfo for HydraWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Tokens::Locks` (r:1 w:1) /// Proof: `Tokens::Locks` (`max_values`: None, `max_size`: Some(1261), added: 3736, mode: `MaxEncodedLen`) + /// Storage: `Duster::AccountBlacklist` (r:2 w:0) + /// Proof: `Duster::AccountBlacklist` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::BannedAssets` (r:2 w:0) + /// Proof: `AssetRegistry::BannedAssets` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) /// Storage: `AssetRegistry::Assets` (r:2 w:0) - /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(87), added: 2562, mode: `MaxEncodedLen`) + /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(125), added: 2600, mode: `MaxEncodedLen`) /// The range of component `c` is `[1, 2]`. /// The range of component `b` is `[0, 1]`. - fn calculate_and_execute_buy_in_lbp(c: u32, b: u32) -> Weight { + fn calculate_and_execute_buy_in_lbp(c: u32, b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1567 + b * (1418 ±0)` + // Measured: `1604 + b * (1837 ±0)` // Estimated: `6156 + b * (7749 ±0)` - // Minimum execution time: 75_646_000 picoseconds. - Weight::from_parts(76_052_000, 6156) - // Standard Error: 1_389_058 - .saturating_add(Weight::from_parts(4_096_946, 0).saturating_mul(c.into())) - // Standard Error: 3_000_708 - .saturating_add(Weight::from_parts(250_139_938, 0).saturating_mul(b.into())) + // Minimum execution time: 75_256_000 picoseconds. + Weight::from_parts(76_245_000, 6156) + // Standard Error: 604_587 + .saturating_add(Weight::from_parts(2_376_809, 0).saturating_mul(c.into())) + // Standard Error: 1_327_242 + .saturating_add(Weight::from_parts(273_173_826, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().reads((9_u64).saturating_mul(b.into()))) + .saturating_add(T::DbWeight::get().reads((13_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(b.into()))) .saturating_add(Weight::from_parts(0, 7749).saturating_mul(b.into())) } + /// Storage: `AssetRegistry::Assets` (r:6 w:0) + /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(125), added: 2600, mode: `MaxEncodedLen`) /// Storage: `Router::Routes` (r:1 w:1) /// Proof: `Router::Routes` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) - /// Storage: `Tokens::Accounts` (r:9 w:0) - /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `Tokens::TotalIssuance` (r:2 w:0) - /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `AssetRegistry::Assets` (r:3 w:0) - /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(87), added: 2562, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:4 w:0) + /// Storage: `System::Account` (r:7 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Tokens::Accounts` (r:15 w:0) + /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `XYK::ShareToken` (r:6 w:0) + /// Proof: `XYK::ShareToken` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Duster::AccountBlacklist` (r:7 w:0) + /// Proof: `Duster::AccountBlacklist` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::BannedAssets` (r:5 w:0) + /// Proof: `AssetRegistry::BannedAssets` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) /// Storage: `MultiTransactionPayment::AccountCurrencyMap` (r:1 w:0) /// Proof: `MultiTransactionPayment::AccountCurrencyMap` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MultiTransactionPayment::AcceptedCurrencies` (r:3 w:0) + /// Storage: `MultiTransactionPayment::AcceptedCurrencies` (r:5 w:0) /// Proof: `MultiTransactionPayment::AcceptedCurrencies` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `XYK::ShareToken` (r:3 w:0) - /// Proof: `XYK::ShareToken` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `EmaOracle::Accumulator` (r:1 w:0) /// Proof: `EmaOracle::Accumulator` (`max_values`: Some(1), `max_size`: Some(5921), added: 6416, mode: `MaxEncodedLen`) + /// Storage: `Tokens::TotalIssuance` (r:1 w:0) + /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) fn set_route_for_xyk() -> Weight { // Proof Size summary in bytes: - // Measured: `4201` - // Estimated: `24237` - // Minimum execution time: 1_126_027_000 picoseconds. - Weight::from_parts(1_133_155_000, 24237) - .saturating_add(T::DbWeight::get().reads(27_u64)) + // Measured: `6326` + // Estimated: `39735` + // Minimum execution time: 2_275_922_000 picoseconds. + Weight::from_parts(2_284_697_000, 39735) + .saturating_add(T::DbWeight::get().reads(55_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Router::Routes` (r:0 w:1) + /// Proof: `Router::Routes` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + fn force_insert_route() -> Weight { + // Proof Size summary in bytes: + // Measured: `1012` + // Estimated: `0` + // Minimum execution time: 30_072_000 picoseconds. + Weight::from_parts(30_421_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { /// Storage: `LBP::PoolData` (r:1 w:0) /// Proof: `LBP::PoolData` (`max_values`: None, `max_size`: Some(163), added: 2638, mode: `MaxEncodedLen`) @@ -148,18 +167,22 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Tokens::Locks` (r:1 w:1) /// Proof: `Tokens::Locks` (`max_values`: None, `max_size`: Some(1261), added: 3736, mode: `MaxEncodedLen`) + /// Storage: `Duster::AccountBlacklist` (r:2 w:0) + /// Proof: `Duster::AccountBlacklist` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::BannedAssets` (r:2 w:0) + /// Proof: `AssetRegistry::BannedAssets` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) /// Storage: `AssetRegistry::Assets` (r:2 w:0) - /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(87), added: 2562, mode: `MaxEncodedLen`) + /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(125), added: 2600, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1]`. - fn calculate_and_execute_sell_in_lbp(c: u32) -> Weight { + fn calculate_and_execute_sell_in_lbp(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3016` + // Measured: `3436` // Estimated: `13905` - // Minimum execution time: 316_311_000 picoseconds. - Weight::from_parts(318_353_450, 13905) - // Standard Error: 164_994 - .saturating_add(Weight::from_parts(50_546_750, 0).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(12_u64)) + // Minimum execution time: 342_467_000 picoseconds. + Weight::from_parts(346_028_529, 13905) + // Standard Error: 185_098 + .saturating_add(Weight::from_parts(50_586_970, 0).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(16_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `LBP::PoolData` (r:1 w:0) @@ -170,50 +193,68 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Tokens::Locks` (r:1 w:1) /// Proof: `Tokens::Locks` (`max_values`: None, `max_size`: Some(1261), added: 3736, mode: `MaxEncodedLen`) + /// Storage: `Duster::AccountBlacklist` (r:2 w:0) + /// Proof: `Duster::AccountBlacklist` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::BannedAssets` (r:2 w:0) + /// Proof: `AssetRegistry::BannedAssets` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) /// Storage: `AssetRegistry::Assets` (r:2 w:0) - /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(87), added: 2562, mode: `MaxEncodedLen`) + /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(125), added: 2600, mode: `MaxEncodedLen`) /// The range of component `c` is `[1, 2]`. /// The range of component `b` is `[0, 1]`. - fn calculate_and_execute_buy_in_lbp(c: u32, b: u32) -> Weight { + fn calculate_and_execute_buy_in_lbp(c: u32, b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1567 + b * (1418 ±0)` + // Measured: `1604 + b * (1837 ±0)` // Estimated: `6156 + b * (7749 ±0)` - // Minimum execution time: 75_646_000 picoseconds. - Weight::from_parts(76_052_000, 6156) - // Standard Error: 1_389_058 - .saturating_add(Weight::from_parts(4_096_946, 0).saturating_mul(c.into())) - // Standard Error: 3_000_708 - .saturating_add(Weight::from_parts(250_139_938, 0).saturating_mul(b.into())) + // Minimum execution time: 75_256_000 picoseconds. + Weight::from_parts(76_245_000, 6156) + // Standard Error: 604_587 + .saturating_add(Weight::from_parts(2_376_809, 0).saturating_mul(c.into())) + // Standard Error: 1_327_242 + .saturating_add(Weight::from_parts(273_173_826, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().reads((9_u64).saturating_mul(b.into()))) + .saturating_add(RocksDbWeight::get().reads((13_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(b.into()))) .saturating_add(Weight::from_parts(0, 7749).saturating_mul(b.into())) } + /// Storage: `AssetRegistry::Assets` (r:6 w:0) + /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(125), added: 2600, mode: `MaxEncodedLen`) /// Storage: `Router::Routes` (r:1 w:1) /// Proof: `Router::Routes` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) - /// Storage: `Tokens::Accounts` (r:9 w:0) - /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `Tokens::TotalIssuance` (r:2 w:0) - /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `AssetRegistry::Assets` (r:3 w:0) - /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(87), added: 2562, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:4 w:0) + /// Storage: `System::Account` (r:7 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Tokens::Accounts` (r:15 w:0) + /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `XYK::ShareToken` (r:6 w:0) + /// Proof: `XYK::ShareToken` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Duster::AccountBlacklist` (r:7 w:0) + /// Proof: `Duster::AccountBlacklist` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::BannedAssets` (r:5 w:0) + /// Proof: `AssetRegistry::BannedAssets` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) /// Storage: `MultiTransactionPayment::AccountCurrencyMap` (r:1 w:0) /// Proof: `MultiTransactionPayment::AccountCurrencyMap` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `MultiTransactionPayment::AcceptedCurrencies` (r:3 w:0) + /// Storage: `MultiTransactionPayment::AcceptedCurrencies` (r:5 w:0) /// Proof: `MultiTransactionPayment::AcceptedCurrencies` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `XYK::ShareToken` (r:3 w:0) - /// Proof: `XYK::ShareToken` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `EmaOracle::Accumulator` (r:1 w:0) /// Proof: `EmaOracle::Accumulator` (`max_values`: Some(1), `max_size`: Some(5921), added: 6416, mode: `MaxEncodedLen`) + /// Storage: `Tokens::TotalIssuance` (r:1 w:0) + /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) fn set_route_for_xyk() -> Weight { // Proof Size summary in bytes: - // Measured: `4201` - // Estimated: `24237` - // Minimum execution time: 1_126_027_000 picoseconds. - Weight::from_parts(1_133_155_000, 24237) - .saturating_add(RocksDbWeight::get().reads(27_u64)) + // Measured: `6326` + // Estimated: `39735` + // Minimum execution time: 2_275_922_000 picoseconds. + Weight::from_parts(2_284_697_000, 39735) + .saturating_add(RocksDbWeight::get().reads(55_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Router::Routes` (r:0 w:1) + /// Proof: `Router::Routes` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + fn force_insert_route() -> Weight { + // Proof Size summary in bytes: + // Measured: `1012` + // Estimated: `0` + // Minimum execution time: 30_072_000 picoseconds. + Weight::from_parts(30_421_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/runtime/adapters/Cargo.toml b/runtime/adapters/Cargo.toml index 494661492..01737a417 100644 --- a/runtime/adapters/Cargo.toml +++ b/runtime/adapters/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-adapters" -version = "1.2.4" +version = "1.2.5" description = "Structs and other generic types for building runtimes." authors = ["GalacticCouncil"] edition = "2021" diff --git a/runtime/adapters/src/tests/mock.rs b/runtime/adapters/src/tests/mock.rs index aa2a222ea..9a96428b6 100644 --- a/runtime/adapters/src/tests/mock.rs +++ b/runtime/adapters/src/tests/mock.rs @@ -361,6 +361,7 @@ impl pallet_route_executor::Config for Test { type InspectRegistry = MockedAssetRegistry; type AMM = Pools; type DefaultRoutePoolType = DefaultRoutePoolType; + type TechnicalOrigin = EnsureRoot; type WeightInfo = (); } diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index e3c818bbe..c90d4e2a5 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-runtime" -version = "223.0.0" +version = "224.0.0" authors = ["GalacticCouncil"] edition = "2021" license = "Apache 2.0" diff --git a/runtime/hydradx/src/assets.rs b/runtime/hydradx/src/assets.rs index 4d30dfa85..9e7d9cd6f 100644 --- a/runtime/hydradx/src/assets.rs +++ b/runtime/hydradx/src/assets.rs @@ -961,6 +961,11 @@ impl AmmTradeWeights> for RouterWeightInfo { weight } + + fn force_insert_route_weight() -> Weight { + //Since we don't have any AMM specific thing in the extrinsic, we just return the plain weight + weights::route_executor::HydraWeight::::force_insert_route() + } } parameter_types! { @@ -977,6 +982,7 @@ impl pallet_route_executor::Config for Runtime { type DefaultRoutePoolType = DefaultRoutePoolType; type NativeAssetId = NativeAssetId; type InspectRegistry = AssetRegistry; + type TechnicalOrigin = SuperMajorityTechCommittee; } parameter_types! { diff --git a/runtime/hydradx/src/benchmarking/route_executor.rs b/runtime/hydradx/src/benchmarking/route_executor.rs index cdba43295..f52a37884 100644 --- a/runtime/hydradx/src/benchmarking/route_executor.rs +++ b/runtime/hydradx/src/benchmarking/route_executor.rs @@ -17,24 +17,21 @@ #![allow(clippy::result_large_err)] use crate::{ - AccountId, AssetId, Balance, Currencies, InsufficientEDinHDX, Omnipool, Router, Runtime, RuntimeOrigin, System, - LBP, XYK, + AccountId, AssetId, Balance, Currencies, InsufficientEDinHDX, Router, Runtime, RuntimeOrigin, System, LBP, XYK, }; use super::*; use crate::benchmarking::dca::HDX; -use crate::benchmarking::tokens::update_balance; use frame_benchmarking::{account, BenchmarkError}; use frame_support::dispatch::DispatchResult; use frame_support::{assert_ok, ensure}; use frame_system::RawOrigin; +use hydradx_traits::router::inverse_route; use hydradx_traits::router::AssetPair; use hydradx_traits::router::{PoolType, RouterT, Trade}; use orml_benchmarking::runtime_benchmarks; use orml_traits::{MultiCurrency, MultiCurrencyExtended}; use primitives::constants::currency::UNITS; -use sp_runtime::FixedU128; -use sp_runtime::Permill; use sp_std::vec; pub const INITIAL_BALANCE: Balance = 10_000_000 * UNITS; @@ -224,23 +221,20 @@ runtime_benchmarks! { create_xyk_pool(asset_3, asset_4); create_xyk_pool(asset_4, asset_5); create_xyk_pool(asset_5, asset_6); + create_xyk_pool(HDX, asset_6); //INIT OMNIPOOL - let acc = Omnipool::protocol_account(); + /*let acc = Omnipool::protocol_account(); crate::benchmarking::omnipool::init()?; // Create account for token provider and set balance let owner: AccountId = account("owner", 0, 1); - let token_price = FixedU128::from((5,1)); let token_amount = 100000 * UNITS; - //1000000000000000 - update_balance(asset_6, &acc, token_amount); - // Add the token to the pool - Omnipool::add_token(RawOrigin::Root.into(), asset_6, token_price, Permill::from_percent(100), owner)?; + Omnipool::add_token(RawOrigin::Root.into(), asset_6, token_price, Permill::from_percent(100), owner)?;*/ - let better_route = vec![Trade { + let route = vec![Trade { pool: PoolType::XYK, asset_in: HDX, asset_out: asset_2 @@ -261,6 +255,18 @@ runtime_benchmarks! { asset_in: asset_5, asset_out: asset_6 }]; + Router::set_route( + RawOrigin::Signed(caller.clone()).into(), + AssetPair::new(HDX, asset_6), + route, + )?; + + let better_route = vec![Trade { + pool: PoolType::XYK, + asset_in: HDX, + asset_out: asset_6 + },]; + }: { Router::set_route( RawOrigin::Signed(caller.clone()).into(), @@ -272,6 +278,56 @@ runtime_benchmarks! { let stored_route = Router::route(AssetPair::new(HDX, asset_6)).unwrap(); assert_eq!(stored_route, better_route); } + + force_insert_route { + 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"))?; + let asset_3 = register_asset(b"AS3".to_vec(), 1u128).map_err(|_| BenchmarkError::Stop("Failed to register asset"))?; + let asset_4 = register_asset(b"AS4".to_vec(), 1u128).map_err(|_| BenchmarkError::Stop("Failed to register asset"))?; + let asset_5 = register_asset(b"AS5".to_vec(), 1u128).map_err(|_| BenchmarkError::Stop("Failed to register asset"))?; + let asset_6 = register_asset(b"AS6".to_vec(), 1u128).map_err(|_| BenchmarkError::Stop("Failed to register asset"))?; + + let caller: AccountId = funded_account("caller", 0, &[asset_1, asset_2,asset_3]); + create_xyk_pool(HDX, asset_2); + create_xyk_pool(asset_2, asset_3); + create_xyk_pool(asset_3, asset_4); + create_xyk_pool(asset_4, asset_5); + create_xyk_pool(asset_5, asset_6); + create_xyk_pool(HDX, asset_6); + + let route = vec![Trade { + pool: PoolType::XYK, + asset_in: asset_6, + asset_out: asset_5 + },Trade { + pool: PoolType::XYK, + asset_in: asset_5, + asset_out: asset_4 + },Trade { + pool: PoolType::XYK, + asset_in: asset_4, + asset_out: asset_3 + },Trade { + pool: PoolType::XYK, + asset_in: asset_3, + asset_out: asset_2 + },Trade { + pool: PoolType::XYK, + asset_in: asset_2, + asset_out: HDX + }]; + }: { + Router::force_insert_route( + RawOrigin::Root.into(), + AssetPair::new(asset_6, HDX), + route.clone(), + )?; + } + verify { + + let stored_route = Router::route(AssetPair::new(HDX, asset_6)).unwrap(); + assert_eq!(inverse_route(stored_route.to_vec()), route); + } } #[cfg(test)] diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 0731cf3ff..f6586e87d 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -109,7 +109,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("hydradx"), impl_name: create_runtime_str!("hydradx"), authoring_version: 1, - spec_version: 223, + spec_version: 224, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/runtime/hydradx/src/weights/route_executor.rs b/runtime/hydradx/src/weights/route_executor.rs index ad6a8b7b6..10f017e21 100644 --- a/runtime/hydradx/src/weights/route_executor.rs +++ b/runtime/hydradx/src/weights/route_executor.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for `pallet_route_executor` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-03-05, STEPS: `10`, REPEAT: `30`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-18, STEPS: `10`, REPEAT: `30`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bench-bot`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 @@ -33,8 +33,8 @@ // --wasm-execution=compiled // --heap-pages=4096 // --template=.maintain/pallet-weight-template-no-back.hbs -// --pallet=pallet-route-executor -// --output=router.rs +// --pallet=pallet_route-executor +// --output=re2.rs // --extrinsic=* #![cfg_attr(rustfmt, rustfmt_skip)] @@ -67,10 +67,10 @@ impl pallet_route_executor::weights::WeightInfo for Hyd // Proof Size summary in bytes: // Measured: `3436` // Estimated: `13905` - // Minimum execution time: 347_725_000 picoseconds. - Weight::from_parts(351_096_698, 13905) - // Standard Error: 200_537 - .saturating_add(Weight::from_parts(50_253_676, 0).saturating_mul(c.into())) + // Minimum execution time: 344_173_000 picoseconds. + Weight::from_parts(347_378_169, 13905) + // Standard Error: 131_839 + .saturating_add(Weight::from_parts(49_213_080, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(16)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -93,79 +93,57 @@ impl pallet_route_executor::weights::WeightInfo for Hyd fn calculate_and_execute_buy_in_lbp(c: u32, b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1604 + b * (1837 ±0)` - // Estimated: `6156 + b * (7749 ±99_524_913_928_918_768)` - // Minimum execution time: 76_051_000 picoseconds. - Weight::from_parts(76_610_000, 6156) - // Standard Error: 604_305 - .saturating_add(Weight::from_parts(2_329_553, 0).saturating_mul(c.into())) - // Standard Error: 1_326_623 - .saturating_add(Weight::from_parts(278_434_394, 0).saturating_mul(b.into())) + // Estimated: `6156 + b * (7749 ±251_795_645_551_580_832)` + // Minimum execution time: 75_692_000 picoseconds. + Weight::from_parts(76_409_000, 6156) + // Standard Error: 611_234 + .saturating_add(Weight::from_parts(2_382_471, 0).saturating_mul(c.into())) + // Standard Error: 1_341_833 + .saturating_add(Weight::from_parts(272_805_599, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().reads((13_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(b.into()))) .saturating_add(Weight::from_parts(0, 7749).saturating_mul(b.into())) } - /// Storage: `AssetRegistry::Assets` (r:7 w:0) + /// Storage: `AssetRegistry::Assets` (r:6 w:0) /// Proof: `AssetRegistry::Assets` (`max_values`: None, `max_size`: Some(125), added: 2600, mode: `MaxEncodedLen`) /// Storage: `Router::Routes` (r:1 w:1) /// Proof: `Router::Routes` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) - /// Storage: `Omnipool::Assets` (r:2 w:0) - /// Proof: `Omnipool::Assets` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:8 w:0) + /// Storage: `System::Account` (r:7 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Tokens::Accounts` (r:16 w:0) + /// Storage: `Tokens::Accounts` (r:15 w:0) /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `Omnipool::HubAssetImbalance` (r:1 w:0) - /// Proof: `Omnipool::HubAssetImbalance` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) - /// Storage: `DynamicFees::AssetFee` (r:2 w:0) - /// Proof: `DynamicFees::AssetFee` (`max_values`: None, `max_size`: Some(24), added: 2499, mode: `MaxEncodedLen`) - /// Storage: `EmaOracle::Oracles` (r:2 w:0) - /// Proof: `EmaOracle::Oracles` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `XYK::ShareToken` (r:6 w:0) + /// Proof: `XYK::ShareToken` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Duster::AccountBlacklist` (r:7 w:0) /// Proof: `Duster::AccountBlacklist` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `AssetRegistry::BannedAssets` (r:5 w:0) /// Proof: `AssetRegistry::BannedAssets` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) - /// Storage: `MultiTransactionPayment::AccountCurrencyMap` (r:2 w:0) + /// Storage: `MultiTransactionPayment::AccountCurrencyMap` (r:1 w:0) /// Proof: `MultiTransactionPayment::AccountCurrencyMap` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `MultiTransactionPayment::AcceptedCurrencies` (r:5 w:0) /// Proof: `MultiTransactionPayment::AcceptedCurrencies` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `EmaOracle::Accumulator` (r:1 w:0) /// Proof: `EmaOracle::Accumulator` (`max_values`: Some(1), `max_size`: Some(5921), added: 6416, mode: `MaxEncodedLen`) - /// Storage: `CircuitBreaker::AllowedTradeVolumeLimitPerAsset` (r:2 w:0) - /// Proof: `CircuitBreaker::AllowedTradeVolumeLimitPerAsset` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) - /// Storage: `CircuitBreaker::TradeVolumeLimitPerAsset` (r:2 w:0) - /// Proof: `CircuitBreaker::TradeVolumeLimitPerAsset` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `CircuitBreaker::LiquidityAddLimitPerAsset` (r:1 w:0) - /// Proof: `CircuitBreaker::LiquidityAddLimitPerAsset` (`max_values`: None, `max_size`: Some(29), added: 2504, mode: `MaxEncodedLen`) - /// Storage: `CircuitBreaker::AllowedAddLiquidityAmountPerAsset` (r:1 w:0) - /// Proof: `CircuitBreaker::AllowedAddLiquidityAmountPerAsset` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `CircuitBreaker::LiquidityRemoveLimitPerAsset` (r:1 w:0) - /// Proof: `CircuitBreaker::LiquidityRemoveLimitPerAsset` (`max_values`: None, `max_size`: Some(29), added: 2504, mode: `MaxEncodedLen`) - /// Storage: `CircuitBreaker::AllowedRemoveLiquidityAmountPerAsset` (r:1 w:0) - /// Proof: `CircuitBreaker::AllowedRemoveLiquidityAmountPerAsset` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Referrals::LinkedAccounts` (r:1 w:0) - /// Proof: `Referrals::LinkedAccounts` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) - /// Storage: `Referrals::AssetRewards` (r:1 w:0) - /// Proof: `Referrals::AssetRewards` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `Referrals::TotalShares` (r:1 w:0) - /// Proof: `Referrals::TotalShares` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Referrals::TraderShares` (r:1 w:0) - /// Proof: `Referrals::TraderShares` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `Referrals::PendingConversions` (r:1 w:0) - /// Proof: `Referrals::PendingConversions` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) - /// Storage: `Referrals::CounterForPendingConversions` (r:1 w:0) - /// Proof: `Referrals::CounterForPendingConversions` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Tokens::TotalIssuance` (r:1 w:0) /// Proof: `Tokens::TotalIssuance` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `XYK::ShareToken` (r:5 w:0) - /// Proof: `XYK::ShareToken` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_route_for_xyk() -> Weight { // Proof Size summary in bytes: - // Measured: `7187` - // Estimated: `42318` - // Minimum execution time: 2_333_578_000 picoseconds. - Weight::from_parts(2_348_750_000, 42318) - .saturating_add(T::DbWeight::get().reads(79)) + // Measured: `6326` + // Estimated: `39735` + // Minimum execution time: 2_263_303_000 picoseconds. + Weight::from_parts(2_275_623_000, 39735) + .saturating_add(T::DbWeight::get().reads(55)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Router::Routes` (r:0 w:1) + /// Proof: `Router::Routes` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + fn force_insert_route() -> Weight { + // Proof Size summary in bytes: + // Measured: `1012` + // Estimated: `0` + // Minimum execution time: 29_861_000 picoseconds. + Weight::from_parts(30_303_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } } \ No newline at end of file diff --git a/traits/Cargo.toml b/traits/Cargo.toml index 115abd37b..dbc0b43e4 100644 --- a/traits/Cargo.toml +++ b/traits/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-traits" -version = "3.1.0" +version = "3.1.1" description = "Shared traits" authors = ["GalacticCouncil"] edition = "2021" diff --git a/traits/src/router.rs b/traits/src/router.rs index 48da2a729..defc39b4a 100644 --- a/traits/src/router.rs +++ b/traits/src/router.rs @@ -121,6 +121,12 @@ pub trait RouterT { fn calculate_buy_trade_amounts(route: &[Trade], amount_out: Balance) -> Result, DispatchError>; fn set_route(origin: Origin, asset_pair: AssetPair, route: Vec) -> DispatchResultWithPostInfo; + + fn force_insert_route( + origin: Origin, + asset_pair: AssetPair, + route: Vec, + ) -> DispatchResultWithPostInfo; } /// All AMMs used in the router are required to implement this trait. @@ -276,6 +282,7 @@ pub trait AmmTradeWeights { fn sell_and_calculate_sell_trade_amounts_weight(route: &[Trade]) -> Weight; fn buy_and_calculate_buy_trade_amounts_weight(route: &[Trade]) -> Weight; fn set_route_weight(route: &[Trade]) -> Weight; + fn force_insert_route_weight() -> Weight; } impl AmmTradeWeights for () { @@ -297,4 +304,7 @@ impl AmmTradeWeights for () { fn set_route_weight(_route: &[Trade]) -> Weight { Weight::zero() } + fn force_insert_route_weight() -> Weight { + Weight::zero() + } }