are_fpdecimals_approximately_equal, assert_fee_is_as_expected, create_realistic_atom_usdt_sell_orders_from_spreadsheet,
create_realistic_eth_usdt_buy_orders_from_spreadsheet, create_realistic_eth_usdt_sell_orders_from_spreadsheet,
create_realistic_inj_usdt_buy_orders_from_spreadsheet, create_realistic_usdt_usdc_both_side_orders, human_to_dec, init_rich_account,
init_self_relaying_contract_and_get_address, initial_coin, launch_realistic_atom_usdt_spot_market, launch_realistic_inj_usdt_spot_market,
launch_realistic_usdt_usdc_spot_market, launch_realistic_weth_usdt_spot_market, must_init_account_with_funds_and_setting_denoms,
query_all_bank_balances, query_bank_balance, set_route_and_assert_success, str_coin, Decimals, ATOM, DEFAULT_ATOMIC_MULTIPLIER,
use injective_test_tube::{Account, Bank, Exchange, InjectiveTestApp, Module, RunnerResult, SigningAccount, Wasm};
https://docs.google.com/spreadsheets/d/1-0epjX580nDO_P2mm1tSjhvjJVppsvrO1BC4_wsBeyA/edit?usp=sharing
pub fn happy_path_two_hops_test(app: InjectiveTestApp, owner: SigningAccount, contr_addr: String) {
create_realistic_eth_usdt_buy_orders_from_spreadsheet(&app, &spot_market_1_id, &trader1, &trader2);
create_realistic_atom_usdt_sell_orders_from_spreadsheet(&app, &spot_market_2_id, &trader1, &trader2, &trader3);
assert_fee_is_as_expected(&mut query_result.expected_fees, &mut expected_fees, human_to_dec("0.1", Decimals::Six));
"Swapper did not receive expected amount. Expected: {} ATOM, actual: {} ATOM, max diff: {} ATOM",
let contract_usdt_balance_before = FPDecimal::must_from_str(contract_balances_before[0].amount.as_str());
let contract_usdt_balance_after = FPDecimal::must_from_str(contract_balances_after[0].amount.as_str());
are_fpdecimals_approximately_equal(contract_usdt_balance_after, contract_usdt_balance_before, max_diff,),
"Contract balance changed too much. Actual balance: {} USDT, previous balance: {} USDT. Max diff: {} USDT",
let _signer = must_init_account_with_funds_and_setting_denoms(&app, &validator, &[initial_coin("1", INJ, Decimals::Eighteen)]);
let contr_addr = init_self_relaying_contract_and_get_address(&wasm, &owner, &[str_coin("1_000", USDT, Decimals::Six)]);
let _signer = must_init_account_with_funds_and_setting_denoms(&app, &validator, &[initial_coin("1", INJ, Decimals::Eighteen)]);
let contr_addr = init_self_relaying_contract_and_get_address(&wasm, &owner, &[str_coin("1_000", USDT, Decimals::Six)]);
create_realistic_inj_usdt_buy_orders_from_spreadsheet(&app, &spot_market_1_id, &trader1, &trader2);
create_realistic_eth_usdt_sell_orders_from_spreadsheet(&app, &spot_market_2_id, &trader1, &trader2, &trader3);
assert_fee_is_as_expected(&mut query_result.expected_fees, &mut expected_fees, human_to_dec("0.1", Decimals::Six));
let contract_usdt_balance_before = FPDecimal::must_from_str(contract_balances_before[0].amount.as_str());
let contract_usdt_balance_after = FPDecimal::must_from_str(contract_balances_after[0].amount.as_str());
are_fpdecimals_approximately_equal(contract_usdt_balance_after, contract_usdt_balance_before, max_diff,),
"Contract balance changed too much. Actual balance: {} USDT, previous balance: {} USDT. Max diff: {} USDT",
let _signer = must_init_account_with_funds_and_setting_denoms(&app, &validator, &[initial_coin("1", INJ, Decimals::Eighteen)]);
let contr_addr = init_self_relaying_contract_and_get_address(&wasm, &owner, &[str_coin("1_000", USDT, Decimals::Six)]);
create_realistic_inj_usdt_buy_orders_from_spreadsheet(&app, &spot_market_1_id, &trader1, &trader2);
create_realistic_atom_usdt_sell_orders_from_spreadsheet(&app, &spot_market_2_id, &trader1, &trader2, &trader3);
assert_fee_is_as_expected(&mut query_result.expected_fees, &mut expected_fees, human_to_dec("0.1", Decimals::Six));
"Swapper did not receive expected amount. Expected: {} ATOM, actual: {} ATOM, max diff: {} ATOM",
let contract_usdt_balance_before = FPDecimal::must_from_str(contract_balances_before[0].amount.as_str());
let contract_usdt_balance_after = FPDecimal::must_from_str(contract_balances_after[0].amount.as_str());
are_fpdecimals_approximately_equal(contract_usdt_balance_after, contract_usdt_balance_before, max_diff,),
let _signer = must_init_account_with_funds_and_setting_denoms(&app, &validator, &[initial_coin("1", INJ, Decimals::Eighteen)]);
create_realistic_inj_usdt_buy_orders_from_spreadsheet(&app, &spot_market_1_id, &trader1, &trader2);
assert_fee_is_as_expected(&mut query_result.expected_fees, &mut expected_fees, human_to_dec("0.1", Decimals::Six));
"Swapper did not receive expected amount. Expected: {} USDC, actual: {} USDC, max diff: {} USDC",
let contract_usdt_balance_before = FPDecimal::must_from_str(contract_balances_before[0].amount.as_str());
let contract_usdt_balance_after = FPDecimal::must_from_str(contract_balances_after[0].amount.as_str());
are_fpdecimals_approximately_equal(contract_usdt_balance_after, contract_usdt_balance_before, max_diff,),
"Contract balance changed too much. Actual balance: {} USDT, previous balance: {} USDT. Max diff: {} USDT",
let contract_usdc_balance_before = FPDecimal::must_from_str(contract_balances_before[1].amount.as_str());
let contract_usdc_balance_after = FPDecimal::must_from_str(contract_balances_after[1].amount.as_str());
are_fpdecimals_approximately_equal(contract_usdc_balance_after, contract_usdc_balance_before, max_diff,),
"Contract balance changed too much. Actual balance: {} USDC, previous balance: {} USDC. Max diff: {} USDC",
let _signer = must_init_account_with_funds_and_setting_denoms(&app, &validator, &[initial_coin("1", INJ, Decimals::Eighteen)]);
let contr_addr = init_self_relaying_contract_and_get_address(&wasm, &owner, &[str_coin("1_000", USDT, Decimals::Six)]);
create_realistic_eth_usdt_buy_orders_from_spreadsheet(&app, &spot_market_1_id, &trader1, &trader2);
create_realistic_atom_usdt_sell_orders_from_spreadsheet(&app, &spot_market_2_id, &trader1, &trader2, &trader3);
let contract_balance_usdt_after = FPDecimal::must_from_str(contract_balances_after[0].amount.as_str());
let contract_balance_usdt_before = FPDecimal::must_from_str(contract_balances_before[0].amount.as_str());
// single swap with the same values results in < 0.7 USDT earning, so we expected that 100 same swaps
are_fpdecimals_approximately_equal(contract_balance_usdt_after, contract_balance_usdt_before, max_diff,),
This test shows that query overestimates the amount of USDT needed to execute the swap. It seems
fn it_correctly_calculates_required_funds_when_querying_buy_with_minimum_buffer_and_realistic_values() {
let _signer = must_init_account_with_funds_and_setting_denoms(&app, &validator, &[initial_coin("1", INJ, Decimals::Eighteen)]);
let contr_addr = init_self_relaying_contract_and_get_address(&wasm, &owner, &[str_coin("51", USDT, Decimals::Six)]);
create_realistic_eth_usdt_buy_orders_from_spreadsheet(&app, &spot_market_1_id, &trader1, &trader2);
create_realistic_atom_usdt_sell_orders_from_spreadsheet(&app, &spot_market_2_id, &trader1, &trader2, &trader3);
let expected_contract_usdt_balance = FPDecimal::must_from_str(contract_balances_before[0].amount.as_str()) + dust_value;
let actual_contract_balance = FPDecimal::must_from_str(contract_balances_after[0].amount.as_str());
// here the actual difference is 0.000067 USDT, which we attribute differences between decimal precision of Rust/Go and Google Sheets
This test shows that in some edge cases we calculate required funds differently than the chain does.
When estimating balance hold for atomic market order chain doesn't take into account whether sender is
also fee recipient, while we do. This leads to a situation where we estimate required funds to be
fn it_correctly_calculates_required_funds_when_executing_buy_with_minimum_buffer_and_realistic_values() {
let _signer = must_init_account_with_funds_and_setting_denoms(&app, &validator, &[initial_coin("1", INJ, Decimals::Eighteen)]);
// in reality we need to add at least 49 USDT to the buffer, even if according to contract's calculations 42 USDT would be enough to execute the swap
let contr_addr = init_self_relaying_contract_and_get_address(&wasm, &owner, &[str_coin("42", USDT, Decimals::Six)]);
create_realistic_eth_usdt_buy_orders_from_spreadsheet(&app, &spot_market_1_id, &trader1, &trader2);
create_realistic_atom_usdt_sell_orders_from_spreadsheet(&app, &spot_market_2_id, &trader1, &trader2, &trader3);
let contract_usdt_balance_before = FPDecimal::must_from_str(contract_balances_before[0].amount.as_str());
let contract_usdt_balance_after = FPDecimal::must_from_str(contract_balances_after[0].amount.as_str());
are_fpdecimals_approximately_equal(contract_usdt_balance_after, contract_usdt_balance_before, max_diff,),
let _signer = must_init_account_with_funds_and_setting_denoms(&app, &validator, &[initial_coin("1", INJ, Decimals::Eighteen)]);
let contr_addr = init_self_relaying_contract_and_get_address(&wasm, &owner, &[str_coin("41", USDT, Decimals::Six)]);
create_realistic_eth_usdt_buy_orders_from_spreadsheet(&app, &spot_market_1_id, &trader1, &trader2);
create_realistic_atom_usdt_sell_orders_from_spreadsheet(&app, &spot_market_2_id, &trader1, &trader2, &trader3);
assert_eq!(contract_balances_before.len(), 1, "wrong number of denoms in contract balances");