From bb89b41edba262f4d73456fab2b677ec53fb8f9f Mon Sep 17 00:00:00 2001 From: Jeremy Liu <31809888+NotJeremyLiu@users.noreply.github.com> Date: Fri, 10 Nov 2023 12:14:20 -0700 Subject: [PATCH 1/4] Add max spread to swap and enforce max spread limit in reverse query --- .../adapters/swap/astroport/src/contract.rs | 19 +++++++++++++++---- .../adapters/swap/astroport/src/error.rs | 3 +++ .../swap/astroport/tests/test_execute_swap.rs | 8 ++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/contracts/adapters/swap/astroport/src/contract.rs b/contracts/adapters/swap/astroport/src/contract.rs index 32bf6f01..c89f09a6 100644 --- a/contracts/adapters/swap/astroport/src/contract.rs +++ b/contracts/adapters/swap/astroport/src/contract.rs @@ -4,14 +4,14 @@ use crate::{ }; use astroport::{ asset::{Asset, AssetInfo}, - pair::{QueryMsg as PairQueryMsg, ReverseSimulationResponse}, + pair::{QueryMsg as PairQueryMsg, ReverseSimulationResponse, MAX_ALLOWED_SLIPPAGE}, router::{ ExecuteMsg as RouterExecuteMsg, QueryMsg as RouterQueryMsg, SimulateSwapOperationsResponse, }, }; use cosmwasm_std::{ - entry_point, to_binary, Addr, Binary, Coin, Deps, DepsMut, Env, MessageInfo, Response, Uint128, - WasmMsg, + entry_point, to_binary, Addr, Binary, Coin, Decimal, Deps, DepsMut, Env, MessageInfo, Response, + Uint128, WasmMsg, }; use cw_utils::one_coin; use skip::swap::{ @@ -131,7 +131,7 @@ fn create_astroport_swap_msg( operations: astroport_swap_operations, minimum_receive: None, to: None, - max_spread: None, + max_spread: Some(MAX_ALLOWED_SLIPPAGE.parse::()?), }; // Create the astroport router swap message @@ -250,6 +250,9 @@ fn query_simulate_swap_exact_coin_out( }, )?; + // Assert the operation does not exceed the max spread limit + assert_max_spread(res.offer_amount, res.spread_amount)?; + Ok(Coin { denom: operation.denom_in.clone(), amount: res.offer_amount.checked_add(Uint128::one())?, @@ -260,3 +263,11 @@ fn query_simulate_swap_exact_coin_out( // Return the coin in needed Ok(coin_in_needed) } + +fn assert_max_spread(return_amount: Uint128, spread_amount: Uint128) -> ContractResult<()> { + let max_spread = MAX_ALLOWED_SLIPPAGE.parse::()?; + if Decimal::from_ratio(spread_amount, return_amount + spread_amount) > max_spread { + return Err(ContractError::MaxSpreadAssertion {}); + } + Ok(()) +} diff --git a/contracts/adapters/swap/astroport/src/error.rs b/contracts/adapters/swap/astroport/src/error.rs index 0dc0312d..bee2e197 100644 --- a/contracts/adapters/swap/astroport/src/error.rs +++ b/contracts/adapters/swap/astroport/src/error.rs @@ -29,4 +29,7 @@ pub enum ContractError { #[error("coin_out denom must match the last swap operation's denom out")] CoinOutDenomMismatch, + + #[error("Operation exceeds max spread limit")] + MaxSpreadAssertion, } diff --git a/contracts/adapters/swap/astroport/tests/test_execute_swap.rs b/contracts/adapters/swap/astroport/tests/test_execute_swap.rs index ed21cfde..1ddbe58a 100644 --- a/contracts/adapters/swap/astroport/tests/test_execute_swap.rs +++ b/contracts/adapters/swap/astroport/tests/test_execute_swap.rs @@ -4,7 +4,7 @@ use astroport::{ }; use cosmwasm_std::{ testing::{mock_dependencies, mock_env, mock_info}, - to_binary, Addr, Coin, + to_binary, Addr, Coin, Decimal, ReplyOn::Never, SubMsg, WasmMsg, }; @@ -69,7 +69,7 @@ struct Params { ], minimum_receive: None, to: None, - max_spread: None, + max_spread: Some(Decimal::percent(50)), })?, funds: vec![Coin::new(100, "uosmo")], } @@ -136,7 +136,7 @@ struct Params { ], minimum_receive: None, to: None, - max_spread: None, + max_spread: Some(Decimal::percent(50)), })?, funds: vec![Coin::new(100, "uosmo")], } @@ -175,7 +175,7 @@ struct Params { operations: vec![], minimum_receive: None, to: None, - max_spread: None, + max_spread: Some(Decimal::percent(50)), })?, funds: vec![Coin::new(100, "uosmo")], } From 755e391bdd308c2967184ad3b0440207f4583439 Mon Sep 17 00:00:00 2001 From: Jeremy Liu <31809888+NotJeremyLiu@users.noreply.github.com> Date: Fri, 10 Nov 2023 12:29:35 -0700 Subject: [PATCH 2/4] assert max spread in simulate swap in query - can't use router any more and instead query the pools directly --- .../adapters/swap/astroport/src/contract.rs | 51 +++++++++++-------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/contracts/adapters/swap/astroport/src/contract.rs b/contracts/adapters/swap/astroport/src/contract.rs index c89f09a6..6e594a17 100644 --- a/contracts/adapters/swap/astroport/src/contract.rs +++ b/contracts/adapters/swap/astroport/src/contract.rs @@ -4,10 +4,11 @@ use crate::{ }; use astroport::{ asset::{Asset, AssetInfo}, - pair::{QueryMsg as PairQueryMsg, ReverseSimulationResponse, MAX_ALLOWED_SLIPPAGE}, - router::{ - ExecuteMsg as RouterExecuteMsg, QueryMsg as RouterQueryMsg, SimulateSwapOperationsResponse, + pair::{ + QueryMsg as PairQueryMsg, ReverseSimulationResponse, SimulationResponse, + MAX_ALLOWED_SLIPPAGE, }, + router::ExecuteMsg as RouterExecuteMsg, }; use cosmwasm_std::{ entry_point, to_binary, Addr, Binary, Coin, Decimal, Deps, DepsMut, Env, MessageInfo, Response, @@ -181,7 +182,7 @@ fn query_simulate_swap_exact_coin_in( swap_operations: Vec, ) -> ContractResult { // Error if swap operations is empty - let (Some(first_op), Some(last_op)) = (swap_operations.first(), swap_operations.last()) else { + let Some(first_op) = swap_operations.first() else { return Err(ContractError::SwapOperationsEmpty); }; @@ -190,29 +191,37 @@ fn query_simulate_swap_exact_coin_in( return Err(ContractError::CoinInDenomMismatch); } - // Get the router contract address - let router_contract_address = ROUTER_CONTRACT_ADDRESS.load(deps.storage)?; - - // Get denom out from last swap operation - let denom_out = last_op.denom_out.clone(); + // Iterate through the swap operations, querying the astroport pool contracts to get the coin out + // for each swap operation, and then updating the coin out for the next swap operation until the + // coin out for the last swap operation is found. + let coin_out = swap_operations.iter().try_fold( + coin_in, + |coin_out, operation| -> Result<_, ContractError> { + let res: SimulationResponse = deps.querier.query_wasm_smart( + &operation.pool, + &PairQueryMsg::Simulation { + offer_asset: Asset { + info: AssetInfo::NativeToken { + denom: coin_out.denom, + }, + amount: coin_out.amount, + }, + ask_asset_info: None, + }, + )?; - // Convert the swap operations to astroport swap operations - let astroport_swap_operations = swap_operations.into_iter().map(From::from).collect(); + // Assert the operation does not exceed the max spread limit + assert_max_spread(res.return_amount, res.spread_amount)?; - // Query the astroport router contract to simulate the swap operations - let res: SimulateSwapOperationsResponse = deps.querier.query_wasm_smart( - router_contract_address, - &RouterQueryMsg::SimulateSwapOperations { - offer_amount: coin_in.amount, - operations: astroport_swap_operations, + Ok(Coin { + denom: operation.denom_out.clone(), + amount: res.return_amount, + }) }, )?; // Return the coin out - Ok(Coin { - denom: denom_out, - amount: res.amount, - }) + Ok(coin_out) } // Queries the astroport pool contracts to simulate a multi-hop swap exact amount out From af7b9d5b35573ff2652558f1761acb3dd32186a1 Mon Sep 17 00:00:00 2001 From: Jeremy Liu <31809888+NotJeremyLiu@users.noreply.github.com> Date: Fri, 10 Nov 2023 13:12:40 -0700 Subject: [PATCH 3/4] update deployed terra mainnet contracts --- deployed-contracts/terra/mainnet.toml | 31 ++++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/deployed-contracts/terra/mainnet.toml b/deployed-contracts/terra/mainnet.toml index 58da313b..f720bb78 100644 --- a/deployed-contracts/terra/mainnet.toml +++ b/deployed-contracts/terra/mainnet.toml @@ -1,30 +1,31 @@ [info] chain_id = "phoenix-1" network = "mainnet" -deploy_date = "01/11/2023 10:49:24" -commit_hash = "e3ece7f86b707183d67521cda2587a20dc59c1e1" +deploy_date = "10/11/2023 12:51:32" +commit_hash = "755e391bdd308c2967184ad3b0440207f4583439" [checksums] "skip_api_entry_point-aarch64.wasm" = "2d4963276cf9504f4d1bcba0e52f9b8f4a774f0e5a84259fffc8db8b8db6fbe9" "skip_api_ibc_adapter_ibc_hooks-aarch64.wasm" = "ae92e2dcd960e589e97dca8b111a8a90fe3cd79869b22a88a7ab6c9f10a75ad5" "skip_api_ibc_adapter_neutron_transfer-aarch64.wasm" = "19951b963dc8fb77eeaca90557d75e918fc9f4096033ea81626b30bc7734c12e" -"skip_api_swap_adapter_astroport-aarch64.wasm" = "cc552b9cba1f6e67601450687c735115799026ac0c786c9b3a5593b448fb2436" +"skip_api_swap_adapter_astroport-aarch64.wasm" = "45b11c1b073b813702103c9c996e52810b997a77319e759422fcef58189a7351" +"skip_api_swap_adapter_lido_satellite-aarch64.wasm" = "fe2a2d2cac64f32a640278cd2d942090b88271f7ef134ce89f57e732253326d3" "skip_api_swap_adapter_osmosis_poolmanager-aarch64.wasm" = "24ab8a5fb42b6c1bfe31833b951a6d287580876f7b5f225d196aa29b5f514cb6" [code-ids] -swap_adapter_contract_code_id = 2017 -ibc_transfer_adapter_contract_code_id = 2018 -entry_point_contract_code_id = 2019 +swap_adapter_contract_code_id = "2077" +ibc_transfer_adapter_contract_code_id = "2078" +entry_point_contract_code_id = "2079" [contract-addresses] -swap_adapter_contract_address = "terra1kmw2c99nnzmr7klt3c0z5ajtkml90gu4luczdmxzc3apkpqttdsql8tdxc" -ibc_transfer_adapter_contract_address = "terra18n9c4auh3h5vwvpqxzy6d0sa4yalczss9fek67jkyshl4kd0t2xsfdcj45" -entry_point_contract_address = "terra1k64frfgx3k5vxzkawm5lhtxfktm0s53lufnv2yk7tf3wj06557asraak09" +swap_adapter_contract_address = "terra1t8nee3950224v8uwhavpfvlfatjfjdmlmav8smwheme3d76np2rsl0xenz" +ibc_transfer_adapter_contract_address = "terra16jhtwk36um8kv7mcc0auc6tqknchhn83ym8ldzp2u6n32w5yuq6s693ncm" +entry_point_contract_address = "terra1jzugwhg2fkuzcepmdfyydrhe0k7lzfhzrjgncm8e7430gkvat9hsyz07mw" [tx-hashes] -store_swap_adapter_tx_hash = "37BFE33A5BB832EB0B37F781F85BC1349CDE60A0DD16FF782F1DBB0A0C9784FC" -store_ibc_transfer_adapter_tx_hash = "53AE0FC525D60682F2D4B2A868F562D88A79D252795A9AE246867A747A1E50B6" -store_entry_point_tx_hash = "7209903C1136BAF0C4FF13C9C8E466072488A0752F490029A426FB7D3DDCDE5C" -instantiate_swap_adapter_tx_hash = "0BA1D4F596D96DFCC18583F8F3F0509837A09281F2C115C84B48C2F5127A1AB2" -instantiate_ibc_transfer_adapter_tx_hash = "DA2A3A987114A0DB37841C42D21B2475C126D07AABCB001FA22DE2BCDABFEE7D" -instantiate_entry_point_tx_hash = "21DE3E37DCE55B767CFC326EDED39B1E59C7A75D4819FBFEF8D3E4BFE2FDAB43" +store_swap_adapter_tx_hash = "986b2285c5e426719c2c2934ebe43de1d2dd4c546c7aeb7092129eae9ca63344" +store_ibc_transfer_adapter_tx_hash = "f6e061a3b640ac8c58906b7b85cc8aeeb5034120240daf9e75a2f0e91429188a" +store_entry_point_tx_hash = "aa775f6445ea362fc8a18b7169efe68b6422af4b89075c39841d2004e7a4ffc1" +instantiate_swap_adapter_tx_hash = "5c8f99df082d77be135fd4be92f026ba7d6b13e52567f05666ba840f7a92ba53" +instantiate_ibc_transfer_adapter_tx_hash = "21f282a12a710da1d0213784a1bed94549bba30b924c52a662af92ba703206a3" +instantiate_entry_point_tx_hash = "e660087cdee75e00f6ba50d4bf88cab1640f14a5c5631b32b7cffef3eb31874d" From adf4ef7d7e7ad2711086811c7cbc780e6bd6be40 Mon Sep 17 00:00:00 2001 From: Jeremy Liu <31809888+NotJeremyLiu@users.noreply.github.com> Date: Fri, 10 Nov 2023 14:23:24 -0700 Subject: [PATCH 4/4] update deployed terra testnet contracts --- deployed-contracts/terra/testnet.toml | 31 ++++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/deployed-contracts/terra/testnet.toml b/deployed-contracts/terra/testnet.toml index d3077731..e8471095 100644 --- a/deployed-contracts/terra/testnet.toml +++ b/deployed-contracts/terra/testnet.toml @@ -1,30 +1,31 @@ [info] chain_id = "pisco-1" network = "testnet" -deploy_date = "01/11/2023 19:23:18" -commit_hash = "e3ece7f86b707183d67521cda2587a20dc59c1e1" +deploy_date = "10/11/2023 14:19:56" +commit_hash = "755e391bdd308c2967184ad3b0440207f4583439" [checksums] "skip_api_entry_point-aarch64.wasm" = "2d4963276cf9504f4d1bcba0e52f9b8f4a774f0e5a84259fffc8db8b8db6fbe9" "skip_api_ibc_adapter_ibc_hooks-aarch64.wasm" = "ae92e2dcd960e589e97dca8b111a8a90fe3cd79869b22a88a7ab6c9f10a75ad5" "skip_api_ibc_adapter_neutron_transfer-aarch64.wasm" = "19951b963dc8fb77eeaca90557d75e918fc9f4096033ea81626b30bc7734c12e" -"skip_api_swap_adapter_astroport-aarch64.wasm" = "cc552b9cba1f6e67601450687c735115799026ac0c786c9b3a5593b448fb2436" +"skip_api_swap_adapter_astroport-aarch64.wasm" = "45b11c1b073b813702103c9c996e52810b997a77319e759422fcef58189a7351" +"skip_api_swap_adapter_lido_satellite-aarch64.wasm" = "fe2a2d2cac64f32a640278cd2d942090b88271f7ef134ce89f57e732253326d3" "skip_api_swap_adapter_osmosis_poolmanager-aarch64.wasm" = "24ab8a5fb42b6c1bfe31833b951a6d287580876f7b5f225d196aa29b5f514cb6" [code-ids] -swap_adapter_contract_code_id = 11299 -ibc_transfer_adapter_contract_code_id = 11300 -entry_point_contract_code_id = 11301 +swap_adapter_contract_code_id = "11686" +ibc_transfer_adapter_contract_code_id = "11688" +entry_point_contract_code_id = "11690" [contract-addresses] -swap_adapter_contract_address = "terra1gj6984mw5qshx43882pe53c7xxyd8n9236qgvr7rurqp7r568u6sfekrzq" -ibc_transfer_adapter_contract_address = "terra1m4907dcrmygfhh24v75kfxukg4l9ke9584udhy2rd539nlppw7wq26lzcm" -entry_point_contract_address = "terra1k64frfgx3k5vxzkawm5lhtxfktm0s53lufnv2yk7tf3wj06557asraak09" +swap_adapter_contract_address = "terra16lh9s0wewq8ffq0v7fx89ds6xnzavr8krg920kh5udazc09lwwssafty4w" +ibc_transfer_adapter_contract_address = "terra17qn3saulgyskcwcfc6x5te8m52lv505zef4xvz8pe0dkzdsl795qar9z5z" +entry_point_contract_address = "terra1jzugwhg2fkuzcepmdfyydrhe0k7lzfhzrjgncm8e7430gkvat9hsyz07mw" [tx-hashes] -store_swap_adapter_tx_hash = "7A8117ACC20FB453570FDED99B0A0DB22009E0C565A8363E937D648A64C6D717" -store_ibc_transfer_adapter_tx_hash = "7890B2181CE200FBFEC3507CC75B6B23CFE889D3B59D36467B36027D7444E57F" -store_entry_point_tx_hash = "D51715FEA312A4412C2AE0C2BF9B6182303D4956016E8DFE0F10DA91DBC83EB6" -instantiate_swap_adapter_tx_hash = "CCF36D9D4650D1FEB28E97293AAAC5A8651694129F5C80AD1F300D47C88413B9" -instantiate_ibc_transfer_adapter_tx_hash = "297BFC5A87B6DFF022BE3456303F89DCA38951FC68D6C11E2516C577AF0CC513" -instantiate_entry_point_tx_hash = "89D30A44C93BB3B138731A653AE6D5AF7E5B3EFCF6A8A677C99B0293FD275910" +store_swap_adapter_tx_hash = "a6a8fb7dff6ccad700565760797f5e170a06a5cf850f79c2f3ebcfb5dbecdc2f" +store_ibc_transfer_adapter_tx_hash = "1fdc19f9770d02fe3482bb03e800af1464bb22aad2adf7da977e74d135a6eb3d" +store_entry_point_tx_hash = "4adb5bb4a862e0932fcea4813e6edba01cc34d7a31e3ca428d2738442a1fbd49" +instantiate_swap_adapter_tx_hash = "bcf206702d1cf4a1ce4f958e8e8f37357c86178f89c63c807e7dfb4a9a8e02d7" +instantiate_ibc_transfer_adapter_tx_hash = "835b308267439c03d6f365553ff63d0e7b6a274f4c29931cff38622adcb37b58" +instantiate_entry_point_tx_hash = "b24f5b2c9519d9051cd273abbc350b76b851675e763849eb8068f77bc9edc0a0"