diff --git a/Cargo.lock b/Cargo.lock index f216dbe62..6bae9a392 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12467,6 +12467,7 @@ dependencies = [ "pretty_assertions", "primitives", "proptest", + "rand 0.8.5", "rococo-runtime", "sc-consensus-grandpa", "scraper", diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 5270a04c6..02f8669d6 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -9,6 +9,7 @@ license = "Apache 2.0" repository = "https://github.com/galacticcouncil/HydraDX-node" [dependencies] +rand = { version = "0.8.5", default-features = false } hex-literal = { workspace = true } frame-remote-externalities = { workspace = true } tokio = { workspace = true } diff --git a/integration-tests/src/ice/generator.rs b/integration-tests/src/ice/generator.rs new file mode 100644 index 000000000..c4362d4bc --- /dev/null +++ b/integration-tests/src/ice/generator.rs @@ -0,0 +1,51 @@ +use pallet_ice::traits::{OmnipoolAssetInfo, OmnipoolInfo}; +use pallet_ice::types::{Intent, Swap, SwapType}; +use primitives::{AccountId, AssetId, Moment}; +use rand::Rng; +use sp_core::crypto::AccountId32; +use sp_runtime::{FixedPointNumber, FixedU128}; + +pub(crate) fn generate_random_intents( + c: u32, + data: Vec>, + deadline: Moment, +) -> Vec> { + let random_pair = || { + let mut rng = rand::thread_rng(); + loop { + let idx_in = rng.gen_range(0..data.len()); + let idx_out = rng.gen_range(0..data.len()); + let reserve_in = data[idx_in].reserve; + let reserve_out = data[idx_out].reserve; + let amount_in = rng.gen_range(1..reserve_in / 4); + let lrna_in = FixedU128::from_rational(amount_in, reserve_in) + .checked_mul_int(data[idx_in].hub_reserve) + .unwrap(); + let amount_out = FixedU128::from_rational(reserve_out, data[idx_out].hub_reserve) + .checked_mul_int(lrna_in) + .unwrap(); + return (data[idx_in].asset_id, data[idx_out].asset_id, amount_in, amount_out); + } + }; + + let mut intents = Vec::new(); + for i in 0..c { + let who: [u8; 32] = [i as u8; 32]; + let (asset_in, asset_out, amount_in, amount_out) = random_pair(); + intents.push(Intent { + who: who.into(), + swap: Swap { + asset_in, + asset_out, + amount_in, + amount_out, + swap_type: SwapType::ExactIn, + }, + deadline, + partial: true, + on_success: None, + on_failure: None, + }); + } + intents +} diff --git a/integration-tests/src/ice/mod.rs b/integration-tests/src/ice/mod.rs index e6574e0d3..742fc4398 100644 --- a/integration-tests/src/ice/mod.rs +++ b/integration-tests/src/ice/mod.rs @@ -1,3 +1,4 @@ +pub(crate) mod generator; mod intents; mod omni; @@ -53,40 +54,18 @@ fn test_omnipool_snapshot() { }); } -pub(crate) fn submit_intents(intents: Vec>) -> Vec { +pub(crate) fn submit_intents(intents: Vec>) -> Vec<(IntentId, Intent)> { let mut intent_ids = Vec::new(); for intent in intents { let deadline = intent.deadline; let increment_id = pallet_ice::Pallet::::next_incremental_id(); - assert_ok!(ICE::submit_intent(RuntimeOrigin::signed(intent.who.clone()), intent,)); + assert_ok!(ICE::submit_intent( + RuntimeOrigin::signed(intent.who.clone()), + intent.clone() + )); let intent_id = pallet_ice::Pallet::::get_intent_id(deadline, increment_id); - intent_ids.push(intent_id); + intent_ids.push((intent_id, intent)); } intent_ids } - -/* - -fn print_json_str(assets: &[OmnipoolAssetInfo]) { - // dump assets info in json format - let mut json = String::from("["); - for asset in assets { - json.push_str(&format!( - r#"{{"asset_id": {}, "reserve": {}, "hub_reserve": {}, "decimals": {}, "fee": {}, "hub_fee": {}, "symbol": "{}"}}"#, - asset.asset_id, - asset.reserve, - asset.hub_reserve, - asset.decimals, - asset.fee.deconstruct(), - asset.hub_fee.deconstruct(), - asset.symbol - )); - json.push_str(","); - } - json.pop(); - json.push_str("]"); - println!("{}", json); -} - - */ diff --git a/integration-tests/src/ice/omni.rs b/integration-tests/src/ice/omni.rs index 4a75ddb66..0d287ed07 100644 --- a/integration-tests/src/ice/omni.rs +++ b/integration-tests/src/ice/omni.rs @@ -1,3 +1,4 @@ +use crate::ice::generator::generate_random_intents; use crate::ice::{solve_intents_with, submit_intents, PATH_TO_SNAPSHOT}; use crate::polkadot_test_net::*; use frame_support::assert_ok; @@ -10,10 +11,12 @@ use hydradx_runtime::{ LRNA as LRNAT, }; use hydradx_traits::router::{PoolType, Trade}; +use pallet_ice::traits::OmnipoolInfo; use pallet_ice::types::{BoundedResolvedIntents, BoundedTrades, Intent, IntentId, Swap}; use pallet_ice::Call::submit_intent; use pallet_omnipool::types::Tradability; use primitives::{AccountId, AssetId, Moment}; +use sp_core::crypto::AccountId32; use sp_runtime::traits::BlockNumberProvider; type PriceP = @@ -28,7 +31,7 @@ fn solver_should_find_solution_with_one_intent() { hydradx_runtime::Balances::set_balance(&BOB.into(), 200_000_000_000_000); let deadline: Moment = Timestamp::now() + 43_200_000; - let intent_ids = submit_intents(vec![Intent { + let intents = submit_intents(vec![Intent { who: BOB.into(), swap: Swap { asset_in: 0, @@ -43,11 +46,6 @@ fn solver_should_find_solution_with_one_intent() { on_failure: None, }]); - let intents = vec![( - intent_ids[0], - pallet_ice::Pallet::::get_intent(intent_ids[0]).unwrap(), - )]; - let resolved = solve_intents_with::(intents).unwrap(); let (trades, score) = @@ -87,7 +85,7 @@ fn execute_solution_should_work_with_one_intent() { hydra_live_ext(PATH_TO_SNAPSHOT).execute_with(|| { hydradx_runtime::Balances::set_balance(&BOB.into(), 200_000_000_000_000); let deadline: Moment = Timestamp::now() + 43_200_000; - let intent_ids = submit_intents(vec![Intent { + let intents = submit_intents(vec![Intent { who: BOB.into(), swap: Swap { asset_in: 0, @@ -102,10 +100,6 @@ fn execute_solution_should_work_with_one_intent() { on_failure: None, }]); - let intents = vec![( - intent_ids[0], - pallet_ice::Pallet::::get_intent(intent_ids[0]).unwrap(), - )]; let resolved = solve_intents_with::(intents).unwrap(); let (trades, score) = @@ -133,7 +127,7 @@ fn execute_solution_should_work_with_two_intents() { )); let deadline: Moment = Timestamp::now() + 43_200_000; - let intent_ids = submit_intents(vec![ + let intents = submit_intents(vec![ Intent { who: BOB.into(), swap: Swap { @@ -164,18 +158,41 @@ fn execute_solution_should_work_with_two_intents() { }, ]); - let intents = vec![ - ( - intent_ids[0], - pallet_ice::Pallet::::get_intent(intent_ids[0]).unwrap(), - ), - ( - intent_ids[1], - pallet_ice::Pallet::::get_intent(intent_ids[1]).unwrap(), - ), - ]; let resolved = solve_intents_with::(intents).unwrap(); + let (trades, score) = + pallet_ice::Pallet::::calculate_trades_and_score(&resolved.to_vec()).unwrap(); + + assert_ok!(ICE::submit_solution( + RuntimeOrigin::signed(BOB.into()), + resolved, + BoundedTrades::try_from(trades).unwrap(), + score, + System::current_block_number() + )); + }); +} + +#[test] +fn execute_solution_should_work_with_multiple_intents() { + hydra_live_ext(PATH_TO_SNAPSHOT).execute_with(|| { + let deadline: Moment = Timestamp::now() + 43_200_000; + let intents = generate_random_intents( + 2, + OmnipoolDataProvider::::assets(None), + deadline, + ); + for intent in intents.iter() { + assert_ok!(Currencies::update_balance( + hydradx_runtime::RuntimeOrigin::root(), + intent.who.clone().into(), + intent.swap.asset_in, + intent.swap.amount_in as i128, + )); + } + let intents = submit_intents(intents); + dbg!(&intents); + let resolved = solve_intents_with::(intents).unwrap(); dbg!(&resolved); let (trades, score) =