Skip to content

Commit

Permalink
Merge pull request #991 from galacticcouncil/integrationt-test-driver
Browse files Browse the repository at this point in the history
feat: add integration test helper
  • Loading branch information
enthusiastmartin authored Jan 21, 2025
2 parents 9ff87be + 98010cd commit a9fe0bc
Show file tree
Hide file tree
Showing 6 changed files with 384 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "runtime-integration-tests"
version = "1.30.1"
version = "1.31.0"
description = "Integration tests"
authors = ["GalacticCouncil"]
edition = "2021"
Expand Down
53 changes: 53 additions & 0 deletions integration-tests/src/driver/example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use crate::driver::HydrationTestDriver;
use crate::polkadot_test_net::*;
use frame_support::assert_ok;
use hydradx_runtime::*;

#[test]
fn driver_test_example() {
HydrationTestDriver::default()
.setup_hydration()
.execute(|| {
assert_ok!(Tokens::set_balance(
RawOrigin::Root.into(),
CHARLIE.into(),
DOT,
20_000_000_000_000_000_000_000_000,
0,
));

assert_ok!(Omnipool::sell(
hydradx_runtime::RuntimeOrigin::signed(CHARLIE.into()),
DOT,
HDX,
1_000_000_000_000,
0u128,
));
})
.new_block()
.execute_with_driver(|driver| {
// This is useful, so we can have access to some info stored in the driver itself
// such as list of omnipool assets or stablepools
let stable_pool_id = driver.stablepools[0].0;
let stable_asset_a = driver.stablepools[0].1[0].0;
let stable_asset_b = driver.stablepools[0].1[1].0;
let stable_asset_a_decimals = driver.stablepools[0].1[0].1 as u32;

assert_ok!(Tokens::set_balance(
RawOrigin::Root.into(),
CHARLIE.into(),
stable_asset_a,
10 * 10u128.pow(stable_asset_a_decimals),
0,
));

assert_ok!(Stableswap::sell(
hydradx_runtime::RuntimeOrigin::signed(CHARLIE.into()),
stable_pool_id,
stable_asset_a,
stable_asset_b,
1u128 * 10u128.pow(stable_asset_a_decimals),
0u128,
));
});
}
327 changes: 327 additions & 0 deletions integration-tests/src/driver/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@
mod example;

use crate::polkadot_test_net::*;
use frame_support::assert_ok;
use frame_support::traits::fungible::Mutate;
use frame_support::BoundedVec;
use hydradx_runtime::*;
use hydradx_traits::stableswap::AssetAmount;
use hydradx_traits::AggregatedPriceOracle;
use pallet_asset_registry::AssetType;
use pallet_stableswap::MAX_ASSETS_IN_POOL;
use primitives::constants::chain::{OMNIPOOL_SOURCE, STABLESWAP_SOURCE};
use primitives::{AccountId, AssetId};
use sp_runtime::{FixedU128, Permill};
use xcm_emulator::TestExt;

pub(crate) struct HydrationTestDriver {
omnipool_assets: Vec<AssetId>,
stablepools: Vec<(AssetId, Vec<(AssetId, u8)>)>,
}

impl HydrationTestDriver {
pub(crate) fn add_omnipool_assets(self, assets: Vec<AssetId>) -> Self {
let mut driver = self;
driver.omnipool_assets.extend(assets);
driver
}

pub(crate) fn add_stablepools(self, pools: Vec<(AssetId, Vec<(AssetId, u8)>)>) -> Self {
let mut driver = self;
driver.stablepools.extend(pools);
driver
}
}

impl HydrationTestDriver {
pub(crate) fn default() -> Self {
TestNet::reset();
HydrationTestDriver {
omnipool_assets: vec![],
stablepools: vec![],
}
}

pub(crate) fn execute(&self, f: impl FnOnce()) -> &Self {
Hydra::ext_wrapper(|| {
f();
});
self
}

pub(crate) fn execute_with_driver(&self, f: impl FnOnce(&Self)) -> &Self {
Hydra::ext_wrapper(|| {
f(self);
});
self
}

pub(crate) fn setup_hydration(self) -> Self {
self.setup_omnipool()
.setup_stableswap()
.add_stablepools_to_omnipool()
.populate_oracle()
}

pub(crate) fn setup_omnipool(self) -> Self {
self.execute(|| {
let acc = hydradx_runtime::Omnipool::protocol_account();
let native_price = FixedU128::from_rational(29903049701668757, 73927734532192294158);
let dot_price = FixedU128::from_rational(103158291366950047, 4566210555614178);

let dot_amount: primitives::Balance = 4566210555614178u128;
let native_amount: primitives::Balance = 73927734532192294158u128;
let weth_amount: primitives::Balance = 1074271742496220564487u128;
let weth_price = FixedU128::from_rational(67852651072676287, 1074271742496220564487);

assert_ok!(Tokens::set_balance(
RawOrigin::Root.into(),
acc.clone(),
DOT,
dot_amount,
0
));
Balances::set_balance(&acc, native_amount);
assert_ok!(Tokens::set_balance(
RawOrigin::Root.into(),
acc.clone(),
WETH,
weth_amount,
0
));

assert_ok!(hydradx_runtime::Omnipool::add_token(
hydradx_runtime::RuntimeOrigin::root(),
HDX,
native_price,
Permill::from_percent(60),
AccountId::from(ALICE),
));

assert_ok!(hydradx_runtime::Omnipool::add_token(
hydradx_runtime::RuntimeOrigin::root(),
DOT,
dot_price,
Permill::from_percent(60),
AccountId::from(ALICE),
));
assert_ok!(hydradx_runtime::Omnipool::add_token(
hydradx_runtime::RuntimeOrigin::root(),
WETH,
weth_price,
Permill::from_percent(60),
AccountId::from(ALICE),
));
});

self.add_omnipool_assets(vec![HDX, DOT, WETH])
}

pub(crate) fn setup_stableswap(self) -> Self {
let mut stable_pool_id = 0;
let mut stable_assets = vec![];
self.execute(|| {
let possible_decimals: Vec<u8> = vec![6u8, 10u8, 12u8, 12u8, 18u8];
let initial_liquidity = 1000u128;
let mut asset_ids: Vec<(AssetId, u8)> = Vec::new();
let mut initial: Vec<AssetAmount<AssetId>> = vec![];

let asset_offset = 555u32;

for idx in 0u32..MAX_ASSETS_IN_POOL {
let name: Vec<u8> = idx.to_ne_bytes().to_vec();
let decimals = possible_decimals[idx as usize % possible_decimals.len() as usize];
let result = AssetRegistry::register(
RawOrigin::Root.into(),
Some(asset_offset + idx),
Some(name.clone().try_into().unwrap()),
AssetType::Token,
Some(1000u128),
Some(name.try_into().unwrap()),
Some(decimals),
None,
None,
true,
);
assert_ok!(result);
let asset_id = asset_offset + idx;
asset_ids.push((asset_id, decimals));

let liquidity = initial_liquidity * 10u128.pow(decimals as u32);

assert_ok!(Currencies::update_balance(
hydradx_runtime::RuntimeOrigin::root(),
AccountId::from(BOB),
asset_id,
liquidity as i128,
));
initial.push(AssetAmount::new(asset_id, liquidity));
}

let pool_id = 222_222u32;
let result = AssetRegistry::register(
RawOrigin::Root.into(),
Some(pool_id),
Some(b"pool".to_vec().try_into().unwrap()),
AssetType::StableSwap,
Some(1u128),
None,
None,
None,
None,
true,
);
assert_ok!(result);
let amplification = 100u16;
let fee = Permill::from_percent(1);

assert_ok!(Stableswap::create_pool(
hydradx_runtime::RuntimeOrigin::root(),
pool_id,
asset_ids.iter().map(|(id, _)| *id).collect(),
amplification,
fee,
));

assert_ok!(Stableswap::add_liquidity(
hydradx_runtime::RuntimeOrigin::signed(BOB.into()),
pool_id,
BoundedVec::truncate_from(initial)
));
stable_pool_id = pool_id;
stable_assets = asset_ids;
});

self.add_stablepools(vec![(stable_pool_id, stable_assets)])
}

pub(crate) fn add_stablepools_to_omnipool(self) -> Self {
self.execute(|| {
let omnipool_acc = hydradx_runtime::Omnipool::protocol_account();
for (pool_id, _) in self.stablepools.iter() {
let pool_id_issuance = Tokens::total_issuance(pool_id);
assert_ok!(hydradx_runtime::Currencies::transfer(
hydradx_runtime::RuntimeOrigin::signed(BOB.into()),
omnipool_acc.clone().into(),
*pool_id,
pool_id_issuance,
));
assert_ok!(hydradx_runtime::Omnipool::add_token(
hydradx_runtime::RuntimeOrigin::root(),
*pool_id,
FixedU128::from_inner(25_650_000_000_000_000),
Permill::from_percent(1),
AccountId::from(BOB),
));
}
});
let stableids = self.stablepools.iter().map(|(pool_id, _)| *pool_id).collect();
self.add_omnipool_assets(stableids)
}

fn populate_oracle(self) -> Self {
//we need to make trades for each asset in omnipool
//for at least 10 block to ensure SHORT oracle is updated too
for _ in 1..=10 {
self.new_block();
let assets = self.omnipool_assets.clone();
let stablepools = self.stablepools.clone();
self.execute(|| {
for asset_id in assets {
let amount_to_sell = 1_000_000_000_000;
assert_ok!(Tokens::set_balance(
RawOrigin::Root.into(),
CHARLIE.into(),
crate::polkadot_test_net::LRNA,
amount_to_sell,
0,
));

assert_ok!(Omnipool::sell(
RuntimeOrigin::signed(CHARLIE.into()),
crate::polkadot_test_net::LRNA,
asset_id,
amount_to_sell,
1
));
}

for (pool_id, assets) in stablepools {
for two_assets in assets.windows(2) {
let asset_a = two_assets[0];
let asset_b = two_assets[1];
let amount = 1u128 * 10u128.pow(asset_a.1 as u32);
assert_ok!(Tokens::set_balance(
RawOrigin::Root.into(),
CHARLIE.into(),
asset_a.0,
amount,
0,
));

assert_ok!(Stableswap::sell(
RuntimeOrigin::signed(CHARLIE.into()),
pool_id,
asset_a.0,
asset_b.0,
amount,
1
));
}
}
});
}

self
}

fn new_block(&self) -> &Self {
self.execute(|| {
hydradx_run_to_next_block();
});
self
}
}

#[test]
fn test_hydration_setup() {
HydrationTestDriver::default()
.setup_hydration()
.execute_with_driver(|driver| {
assert_ok!(Tokens::set_balance(
RawOrigin::Root.into(),
CHARLIE.into(),
DOT,
20_000_000_000_000_000_000_000_000,
0,
));

assert_ok!(Omnipool::sell(
hydradx_runtime::RuntimeOrigin::signed(CHARLIE.into()),
DOT,
HDX,
1_000_000_000_000,
0u128,
));

assert_eq!(driver.omnipool_assets, vec![HDX, DOT, WETH, 222_222]);
assert!(driver.stablepools.len() > 0);

let stablepool_1 = driver.stablepools[0].clone();
let first_asset_id = stablepool_1.1[0].0;
let pool_id = stablepool_1.0;

// assert oracle initial values
for supported_period in crate::oracle::SUPPORTED_PERIODS {
assert!(
EmaOracle::get_price(HDX, crate::polkadot_test_net::LRNA, *supported_period, OMNIPOOL_SOURCE)
.is_ok()
);
assert!(
EmaOracle::get_price(DOT, crate::polkadot_test_net::LRNA, *supported_period, OMNIPOOL_SOURCE)
.is_ok()
);
assert!(EmaOracle::get_price(first_asset_id, pool_id, *supported_period, STABLESWAP_SOURCE).is_ok());
}
});
}
Loading

0 comments on commit a9fe0bc

Please sign in to comment.