diff --git a/smart-contracts/contracts/dex-router-osmosis/.cargo/config.toml b/smart-contracts/contracts/dex-router-osmosis/.cargo/config.toml index f890b1c69..f7b529309 100644 --- a/smart-contracts/contracts/dex-router-osmosis/.cargo/config.toml +++ b/smart-contracts/contracts/dex-router-osmosis/.cargo/config.toml @@ -2,5 +2,5 @@ wasm = "build --release --target wasm32-unknown-unknown" unit-test = "test --lib" schema = "run --bin schema" -test-tube = "test -- --include-ignored --test-threads=1" +test-tube = "test --features test-tube -- --include-ignored --test-threads=1" test-tube-build = "build --release --lib --target wasm32-unknown-unknown --target-dir ./test-tube-build" diff --git a/smart-contracts/contracts/dex-router-osmosis/Cargo.toml b/smart-contracts/contracts/dex-router-osmosis/Cargo.toml index 8e01af1cd..9f9d41da6 100644 --- a/smart-contracts/contracts/dex-router-osmosis/Cargo.toml +++ b/smart-contracts/contracts/dex-router-osmosis/Cargo.toml @@ -25,6 +25,7 @@ name = "schema" [features] default = [] library = [] +test-tube = ["osmosis-test-tube"] [dependencies] cosmwasm-std = { workspace = true } @@ -36,6 +37,4 @@ mars-owner = { workspace = true } osmosis-std = { workspace = true } quasar-types = { workspace = true } prost = { workspace = true } - -[dev-dependencies] -osmosis-test-tube = { workspace = true } \ No newline at end of file +osmosis-test-tube = { workspace = true, optional = true } \ No newline at end of file diff --git a/smart-contracts/contracts/dex-router-osmosis/src/tests/mod.rs b/smart-contracts/contracts/dex-router-osmosis/src/tests/mod.rs index 066cc2f21..0da79ae3f 100644 --- a/smart-contracts/contracts/dex-router-osmosis/src/tests/mod.rs +++ b/smart-contracts/contracts/dex-router-osmosis/src/tests/mod.rs @@ -1,4 +1,3 @@ -mod initialize; mod remove_path; mod set_path; mod swap; diff --git a/smart-contracts/contracts/dex-router-osmosis/src/tests/remove_path.rs b/smart-contracts/contracts/dex-router-osmosis/src/tests/remove_path.rs index 01e4c69a4..5f09f43a5 100644 --- a/smart-contracts/contracts/dex-router-osmosis/src/tests/remove_path.rs +++ b/smart-contracts/contracts/dex-router-osmosis/src/tests/remove_path.rs @@ -1,15 +1,9 @@ use crate::contract::{execute, instantiate}; -use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use crate::msg::{ExecuteMsg, InstantiateMsg}; use crate::state::PATHS; -use crate::tests::initialize::{ - init_test_contract, setup_paths, single_gamm_pool_fixture, PoolWithDenoms, - ADMIN_BALANCE_AMOUNT, DENOM_BASE, DENOM_QUOTE, FEE_DENOM, TESTUBE_BINARY, -}; use crate::ContractError; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; -use cosmwasm_std::Coin; use osmosis_std::types::osmosis::poolmanager::v1beta1::SwapAmountInRoute; -use osmosis_test_tube::{Module, OsmosisTestApp, Wasm}; #[test] fn test_if_not_owner_then_remove_path_fails() { @@ -228,61 +222,3 @@ fn test_remove_one_of_two_paths() { Some(vec![path2]) ); } - -#[test] -#[ignore] -fn test_set_and_remove_path() { - let app = OsmosisTestApp::new(); - - // Create new account with initial funds - let admin = app - .init_account(&[ - Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), - ]) - .unwrap(); - let wasm = Wasm::new(&app); - - let mut pools: Vec = vec![]; - pools = single_gamm_pool_fixture( - &app, - &admin, - vec![DENOM_BASE.to_string(), DENOM_QUOTE.to_string()], - pools, - ); - - let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); - - setup_paths( - &wasm, - &contract_address, - vec![pools[0].pool], - pools[0].denom0.clone(), - pools[0].denom1.clone(), - &admin, - ); - let _ = wasm - .execute( - &contract_address.to_string(), - &ExecuteMsg::RemovePath { - path: vec![pools.first().unwrap().pool], - bidirectional: true, - offer_denom: pools.first().unwrap().denom0.clone(), - ask_denom: pools.first().unwrap().denom1.clone(), - }, - &[], - &admin, - ) - .unwrap(); - - let resp: Result>, osmosis_test_tube::RunnerError> = wasm.query( - contract_address.as_str(), - &QueryMsg::PathsForPair { - offer_denom: pools.first().unwrap().denom0.clone(), - ask_denom: pools.first().unwrap().denom1.clone(), - }, - ); - - assert!(resp.is_err(), "Path not found"); -} diff --git a/smart-contracts/contracts/dex-router-osmosis/src/tests/set_path.rs b/smart-contracts/contracts/dex-router-osmosis/src/tests/set_path.rs index 704a56faa..5fd89bfc5 100644 --- a/smart-contracts/contracts/dex-router-osmosis/src/tests/set_path.rs +++ b/smart-contracts/contracts/dex-router-osmosis/src/tests/set_path.rs @@ -1,16 +1,7 @@ use crate::contract::{execute, instantiate}; use crate::error::ContractError; -use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; -use crate::tests::initialize::{ - init_test_contract, setup_paths, PoolWithDenoms, ADMIN_BALANCE_AMOUNT, DENOM_BASE, DENOM_QUOTE, - FEE_DENOM, TESTUBE_BINARY, -}; +use crate::msg::{ExecuteMsg, InstantiateMsg}; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; -use cosmwasm_std::Coin; -use osmosis_std::types::osmosis::poolmanager::v1beta1::SwapAmountInRoute; -use osmosis_test_tube::{Module, OsmosisTestApp, Wasm}; - -use super::initialize::single_cl_pool_fixture; #[test] fn test_if_not_owner_then_set_path_fails() { @@ -52,61 +43,3 @@ fn test_if_path_is_empty_then_set_path_fails() { let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); assert_eq!(err, ContractError::EmptyPath {}); } - -#[test] -#[ignore] -fn test_set_path_works() { - let app = OsmosisTestApp::new(); - - // Create new account with initial funds - let admin = app - .init_account(&[ - Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), - ]) - .unwrap(); - let wasm = Wasm::new(&app); - - let mut pools: Vec = vec![]; - pools = single_cl_pool_fixture( - &app, - &admin, - vec![DENOM_BASE.to_string(), DENOM_QUOTE.to_string()], - pools, - ); - - let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); - - setup_paths( - &wasm, - &contract_address, - vec![pools[0].pool], - pools[0].denom0.clone(), - pools[0].denom1.clone(), - &admin, - ); - - let resp: Vec> = wasm - .query( - contract_address.as_str(), - &QueryMsg::PathsForPair { - offer_denom: pools.first().unwrap().denom0.clone(), - ask_denom: pools.first().unwrap().denom1.clone(), - }, - ) - .unwrap(); - - // Assert that the set path is included in the response - let expected_path = SwapAmountInRoute { - pool_id: pools.first().unwrap().pool, - token_out_denom: pools.first().unwrap().denom1.clone(), - }; - - let paths_contain_expected = resp.iter().any(|path| path.contains(&expected_path)); - - assert!( - paths_contain_expected, - "Expected path was not found in the response" - ); -} diff --git a/smart-contracts/contracts/dex-router-osmosis/src/tests/swap.rs b/smart-contracts/contracts/dex-router-osmosis/src/tests/swap.rs index b8c9625b9..eb327da03 100644 --- a/smart-contracts/contracts/dex-router-osmosis/src/tests/swap.rs +++ b/smart-contracts/contracts/dex-router-osmosis/src/tests/swap.rs @@ -1,19 +1,10 @@ use crate::contract::{execute, instantiate}; use crate::error::ContractError; use crate::msg::{ExecuteMsg, InstantiateMsg}; -use crate::tests::initialize::{ - perform_swap, query_paths, setup_paths, ADMIN_BALANCE_AMOUNT, DENOM_BASE, DENOM_QUOTE, - FEE_DENOM, INTERMEDIATE_QUOTE, TESTUBE_BINARY, -}; +use cosmwasm_std::coin; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; -use cosmwasm_std::{coin, Coin}; -use osmosis_test_tube::{Module, OsmosisTestApp, SigningAccount, Wasm}; use quasar_types::error::FundsError; -use super::initialize::{ - init_test_contract, single_cl_pool_fixture, single_gamm_pool_fixture, PoolWithDenoms, -}; - #[test] fn test_swap_without_funds_throws() { let mut deps = mock_dependencies(); @@ -51,191 +42,3 @@ fn test_swap_with_too_many_funds_throws() { let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); assert_eq!(err, ContractError::Funds(FundsError::InvalidAssets(1))) } - -#[test] -#[ignore] -fn test_swap_over_single_cl_route() { - let app = OsmosisTestApp::new(); - - // Create new account with initial funds - let admin = app - .init_account(&[ - Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), - ]) - .unwrap(); - let wasm = Wasm::new(&app); - - let mut pools: Vec = vec![]; - pools = single_gamm_pool_fixture( - &app, - &admin, - vec![DENOM_BASE.to_string(), DENOM_QUOTE.to_string()], - pools, - ); - - let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); - - setup_paths( - &wasm, - &contract_address, - vec![pools[0].pool], - pools[0].denom0.clone(), - pools[0].denom1.clone(), - &admin, - ); - let queried_path = query_paths( - &wasm, - &contract_address, - pools[0].denom0.clone(), - pools[0].denom1.clone(), - ) - .unwrap(); - - assert!(perform_swap( - &wasm, - &contract_address, - pools[0].denom0.clone(), - pools[0].denom1.clone(), - queried_path, - &admin - ) - .is_ok()); -} - -#[test] -#[ignore] -fn test_swap_over_single_gamm_route() { - let app = OsmosisTestApp::new(); - - // Create new account with initial funds - let admin = app - .init_account(&[ - Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), - ]) - .unwrap(); - let wasm = Wasm::new(&app); - let mut pools: Vec = vec![]; - pools = single_gamm_pool_fixture( - &app, - &admin, - vec![DENOM_BASE.to_string(), DENOM_QUOTE.to_string()], - pools, - ); - - let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); - - setup_paths( - &wasm, - &contract_address, - vec![pools[0].pool], - pools[0].denom0.clone(), - pools[0].denom1.clone(), - &admin, - ); - let queried_path = query_paths( - &wasm, - &contract_address, - pools[0].denom0.clone(), - pools[0].denom1.clone(), - ) - .unwrap(); - - assert!(perform_swap( - &wasm, - &contract_address, - pools[0].denom0.clone(), - pools[0].denom1.clone(), - queried_path, - &admin - ) - .is_ok()); -} - -#[test] -#[ignore] -fn test_multihop_swap() { - // Case 1: CL / CL - run_test_case(single_cl_pool_fixture, single_cl_pool_fixture); - - // Case 2: GAMM / GAMM - run_test_case(single_gamm_pool_fixture, single_gamm_pool_fixture); - - // Case 3: CL / GAMM - run_test_case(single_cl_pool_fixture, single_gamm_pool_fixture); - - // Case 4: GAMM / CL - run_test_case(single_gamm_pool_fixture, single_cl_pool_fixture); -} - -fn run_test_case( - fixture1: fn( - &OsmosisTestApp, - &SigningAccount, - Vec, - Vec, - ) -> Vec, - fixture2: fn( - &OsmosisTestApp, - &SigningAccount, - Vec, - Vec, - ) -> Vec, -) { - let app = OsmosisTestApp::new(); - - // Create new account with initial funds - let admin = app - .init_account(&[ - Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), - Coin::new(ADMIN_BALANCE_AMOUNT, INTERMEDIATE_QUOTE), - ]) - .unwrap(); - let wasm = Wasm::new(&app); - let mut pools: Vec = vec![]; - pools = fixture1( - &app, - &admin, - vec![DENOM_QUOTE.to_string(), INTERMEDIATE_QUOTE.to_string()], - pools, - ); - pools = fixture2( - &app, - &admin, - vec![INTERMEDIATE_QUOTE.to_string(), DENOM_BASE.to_string()], - pools, - ); - - let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); - - setup_paths( - &wasm, - &contract_address, - vec![pools[0].pool, pools[1].pool], - pools[0].denom0.clone(), - pools[1].denom1.clone(), - &admin, - ); - let queried_path = query_paths( - &wasm, - &contract_address, - pools[0].denom0.clone(), - pools[1].denom1.clone(), - ) - .unwrap(); - - assert!(perform_swap( - &wasm, - &contract_address, - pools[0].denom0.clone(), - pools[1].denom1.clone(), - queried_path, - &admin - ) - .is_ok()); -} diff --git a/smart-contracts/contracts/dex-router-osmosis/src/tests/initialize.rs b/smart-contracts/contracts/dex-router-osmosis/tests/initialize/mod.rs similarity index 86% rename from smart-contracts/contracts/dex-router-osmosis/src/tests/initialize.rs rename to smart-contracts/contracts/dex-router-osmosis/tests/initialize/mod.rs index e3546b31c..1d827d1f3 100644 --- a/smart-contracts/contracts/dex-router-osmosis/src/tests/initialize.rs +++ b/smart-contracts/contracts/dex-router-osmosis/tests/initialize/mod.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use cosmwasm_schema::cw_serde; use cosmwasm_std::{Addr, Attribute, Coin, Decimal, Uint128}; use osmosis_std::types::cosmos::base::v1beta1::Coin as OsmoCoin; @@ -9,6 +7,7 @@ use osmosis_std::types::osmosis::concentratedliquidity::v1beta1::{ }; use osmosis_std::types::osmosis::gamm::v1beta1::MsgJoinPool; use osmosis_std::types::osmosis::poolmanager::v1beta1::{SpotPriceRequest, SwapAmountInRoute}; +use std::str::FromStr; use osmosis_test_tube::osmosis_std::types::osmosis::gamm::poolmodels::balancer::v1beta1::MsgCreateBalancerPool; use osmosis_test_tube::osmosis_std::types::osmosis::gamm::v1beta1::PoolAsset; @@ -22,14 +21,14 @@ use osmosis_test_tube::{ }; use osmosis_test_tube::{ExecuteResponse, Gamm}; -use crate::msg::{BestPathForPairResponse, ExecuteMsg, InstantiateMsg, QueryMsg}; +use dex_router_osmosis::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; pub(crate) const ADMIN_BALANCE_AMOUNT: u128 = 3402823669209384634633746074317682114u128; -pub(crate) const TOKENS_PROVIDED_AMOUNT: &str = "1000000000000"; +const TOKENS_PROVIDED_AMOUNT: &str = "1000000000000"; pub(crate) const FEE_DENOM: &str = "uosmo"; pub(crate) const DENOM_BASE: &str = "udydx"; pub(crate) const DENOM_QUOTE: &str = "uryeth"; -pub(crate) const INTERMEDIATE_QUOTE: &str = "uwosmo"; +pub const INTERMEDIATE_QUOTE: &str = "uwosmo"; pub(crate) const TESTUBE_BINARY: &str = "./test-tube-build/wasm32-unknown-unknown/release/dex_router_osmosis.wasm"; @@ -350,56 +349,3 @@ pub fn perform_swap( admin, ) } - -#[test] -#[ignore] -fn default_init_works() { - let app = OsmosisTestApp::new(); - - // Create new account with initial funds - let admin = app - .init_account(&[ - Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), - Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), - ]) - .unwrap(); - let wasm = Wasm::new(&app); - - let mut pools: Vec = vec![]; - pools = single_gamm_pool_fixture( - &app, - &admin, - vec![DENOM_BASE.to_string(), DENOM_QUOTE.to_string()], - pools, - ); - - let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); - - setup_paths( - &wasm, - &contract_address, - vec![pools[0].pool], - pools[0].denom0.clone(), - pools[0].denom1.clone(), - &admin, - ); - - let resp: BestPathForPairResponse = wasm - .query( - &contract_address.to_string(), - &QueryMsg::BestPathForPair { - offer: Coin::new( - Uint128::from(100000000u128).into(), - pools.first().unwrap().denom0.clone(), - ), - ask_denom: pools.first().unwrap().denom1.clone(), - }, - ) - .unwrap(); - - let mut iter = resp.path.into_iter(); - // under the default setup, we expect the best path to route over pool 1 - assert_eq!(iter.next().unwrap().pool_id, 1); - assert!(iter.next().is_none()); -} diff --git a/smart-contracts/contracts/dex-router-osmosis/tests/integration.rs b/smart-contracts/contracts/dex-router-osmosis/tests/integration.rs new file mode 100644 index 000000000..5af1f04bb --- /dev/null +++ b/smart-contracts/contracts/dex-router-osmosis/tests/integration.rs @@ -0,0 +1,361 @@ +pub mod initialize; +use cosmwasm_std::{Coin, Uint128}; +use dex_router_osmosis::msg::{BestPathForPairResponse, ExecuteMsg, QueryMsg}; +use initialize::{ + init_test_contract, perform_swap, query_paths, setup_paths, single_cl_pool_fixture, + single_gamm_pool_fixture, PoolWithDenoms, ADMIN_BALANCE_AMOUNT, DENOM_BASE, DENOM_QUOTE, + FEE_DENOM, INTERMEDIATE_QUOTE, TESTUBE_BINARY, +}; +use osmosis_std::types::osmosis::poolmanager::v1beta1::SwapAmountInRoute; +use osmosis_test_tube::{Module, OsmosisTestApp, SigningAccount, Wasm}; + +#[test] +fn default_init_works() { + let app = OsmosisTestApp::new(); + + // Create new account with initial funds + let admin = app + .init_account(&[ + Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), + ]) + .unwrap(); + let wasm = Wasm::new(&app); + + let mut pools: Vec = vec![]; + pools = single_gamm_pool_fixture( + &app, + &admin, + vec![DENOM_BASE.to_string(), DENOM_QUOTE.to_string()], + pools, + ); + + let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); + + setup_paths( + &wasm, + &contract_address, + vec![pools[0].pool], + pools[0].denom0.clone(), + pools[0].denom1.clone(), + &admin, + ); + + let resp: BestPathForPairResponse = wasm + .query( + &contract_address.to_string(), + &QueryMsg::BestPathForPair { + offer: Coin::new( + Uint128::from(100000000u128).into(), + pools.first().unwrap().denom0.clone(), + ), + ask_denom: pools.first().unwrap().denom1.clone(), + }, + ) + .unwrap(); + + let mut iter = resp.path.into_iter(); + // under the default setup, we expect the best path to route over pool 1 + assert_eq!(iter.next().unwrap().pool_id, 1); + assert!(iter.next().is_none()); +} + +#[test] +fn test_set_path_works() { + let app = OsmosisTestApp::new(); + + // Create new account with initial funds + let admin = app + .init_account(&[ + Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), + ]) + .unwrap(); + let wasm = Wasm::new(&app); + + let mut pools: Vec = vec![]; + pools = single_cl_pool_fixture( + &app, + &admin, + vec![DENOM_BASE.to_string(), DENOM_QUOTE.to_string()], + pools, + ); + + let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); + + setup_paths( + &wasm, + &contract_address, + vec![pools[0].pool], + pools[0].denom0.clone(), + pools[0].denom1.clone(), + &admin, + ); + + let resp: Vec> = wasm + .query( + contract_address.as_str(), + &QueryMsg::PathsForPair { + offer_denom: pools.first().unwrap().denom0.clone(), + ask_denom: pools.first().unwrap().denom1.clone(), + }, + ) + .unwrap(); + + // Assert that the set path is included in the response + let expected_path = SwapAmountInRoute { + pool_id: pools.first().unwrap().pool, + token_out_denom: pools.first().unwrap().denom1.clone(), + }; + + let paths_contain_expected = resp.iter().any(|path| path.contains(&expected_path)); + + assert!( + paths_contain_expected, + "Expected path was not found in the response" + ); +} + +#[test] +fn test_set_and_remove_path() { + let app = OsmosisTestApp::new(); + + // Create new account with initial funds + let admin = app + .init_account(&[ + Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), + ]) + .unwrap(); + let wasm = Wasm::new(&app); + + let mut pools: Vec = vec![]; + pools = single_gamm_pool_fixture( + &app, + &admin, + vec![DENOM_BASE.to_string(), DENOM_QUOTE.to_string()], + pools, + ); + + let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); + + setup_paths( + &wasm, + &contract_address, + vec![pools[0].pool], + pools[0].denom0.clone(), + pools[0].denom1.clone(), + &admin, + ); + let _ = wasm + .execute( + &contract_address.to_string(), + &ExecuteMsg::RemovePath { + path: vec![pools.first().unwrap().pool], + bidirectional: true, + offer_denom: pools.first().unwrap().denom0.clone(), + ask_denom: pools.first().unwrap().denom1.clone(), + }, + &[], + &admin, + ) + .unwrap(); + + let resp: Result>, osmosis_test_tube::RunnerError> = wasm.query( + contract_address.as_str(), + &QueryMsg::PathsForPair { + offer_denom: pools.first().unwrap().denom0.clone(), + ask_denom: pools.first().unwrap().denom1.clone(), + }, + ); + + assert!(resp.is_err(), "Path not found"); +} + +#[test] +fn test_swap_over_single_cl_route() { + let app = OsmosisTestApp::new(); + + // Create new account with initial funds + let admin = app + .init_account(&[ + Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), + ]) + .unwrap(); + let wasm = Wasm::new(&app); + + let mut pools: Vec = vec![]; + pools = single_gamm_pool_fixture( + &app, + &admin, + vec![DENOM_BASE.to_string(), DENOM_QUOTE.to_string()], + pools, + ); + + let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); + + setup_paths( + &wasm, + &contract_address, + vec![pools[0].pool], + pools[0].denom0.clone(), + pools[0].denom1.clone(), + &admin, + ); + let queried_path = query_paths( + &wasm, + &contract_address, + pools[0].denom0.clone(), + pools[0].denom1.clone(), + ) + .unwrap(); + + assert!(perform_swap( + &wasm, + &contract_address, + pools[0].denom0.clone(), + pools[0].denom1.clone(), + queried_path, + &admin + ) + .is_ok()); +} + +#[test] +fn test_swap_over_single_gamm_route() { + let app = OsmosisTestApp::new(); + + // Create new account with initial funds + let admin = app + .init_account(&[ + Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), + ]) + .unwrap(); + let wasm = Wasm::new(&app); + let mut pools: Vec = vec![]; + pools = single_gamm_pool_fixture( + &app, + &admin, + vec![DENOM_BASE.to_string(), DENOM_QUOTE.to_string()], + pools, + ); + + let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); + + setup_paths( + &wasm, + &contract_address, + vec![pools[0].pool], + pools[0].denom0.clone(), + pools[0].denom1.clone(), + &admin, + ); + let queried_path = query_paths( + &wasm, + &contract_address, + pools[0].denom0.clone(), + pools[0].denom1.clone(), + ) + .unwrap(); + + assert!(perform_swap( + &wasm, + &contract_address, + pools[0].denom0.clone(), + pools[0].denom1.clone(), + queried_path, + &admin + ) + .is_ok()); +} + +#[test] +fn test_multihop_swap() { + // Case 1: CL / CL + run_test_case(single_cl_pool_fixture, single_cl_pool_fixture); + + // Case 2: GAMM / GAMM + run_test_case(single_gamm_pool_fixture, single_gamm_pool_fixture); + + // Case 3: CL / GAMM + run_test_case(single_cl_pool_fixture, single_gamm_pool_fixture); + + // Case 4: GAMM / CL + run_test_case(single_gamm_pool_fixture, single_cl_pool_fixture); +} + +fn run_test_case( + fixture1: fn( + &OsmosisTestApp, + &SigningAccount, + Vec, + Vec, + ) -> Vec, + fixture2: fn( + &OsmosisTestApp, + &SigningAccount, + Vec, + Vec, + ) -> Vec, +) { + let app = OsmosisTestApp::new(); + + // Create new account with initial funds + let admin = app + .init_account(&[ + Coin::new(ADMIN_BALANCE_AMOUNT, FEE_DENOM), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_BASE), + Coin::new(ADMIN_BALANCE_AMOUNT, DENOM_QUOTE), + Coin::new(ADMIN_BALANCE_AMOUNT, INTERMEDIATE_QUOTE), + ]) + .unwrap(); + let wasm = Wasm::new(&app); + let mut pools: Vec = vec![]; + pools = fixture1( + &app, + &admin, + vec![DENOM_QUOTE.to_string(), INTERMEDIATE_QUOTE.to_string()], + pools, + ); + pools = fixture2( + &app, + &admin, + vec![INTERMEDIATE_QUOTE.to_string(), DENOM_BASE.to_string()], + pools, + ); + + let contract_address = init_test_contract(&app, &admin, TESTUBE_BINARY); + + setup_paths( + &wasm, + &contract_address, + vec![pools[0].pool, pools[1].pool], + pools[0].denom0.clone(), + pools[1].denom1.clone(), + &admin, + ); + let queried_path = query_paths( + &wasm, + &contract_address, + pools[0].denom0.clone(), + pools[1].denom1.clone(), + ) + .unwrap(); + + assert!(perform_swap( + &wasm, + &contract_address, + pools[0].denom0.clone(), + pools[1].denom1.clone(), + queried_path, + &admin + ) + .is_ok()); +}