From 0833341b298a60473ba09e233ce96137b2d6c9b7 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Mon, 25 Nov 2024 10:05:31 +0000 Subject: [PATCH 01/21] Added oracle adapter first implementation --- framework/Cargo.lock | 28 + .../packages/standards/oracle/Cargo.toml | 53 ++ framework/packages/standards/oracle/README.md | 5 + .../packages/standards/oracle/src/command.rs | 22 + .../packages/standards/oracle/src/error.rs | 75 +++ .../packages/standards/oracle/src/lib.rs | 13 + .../packages/standards/oracle/src/msg.rs | 51 ++ .../packages/standards/oracle/src/tests.rs | 41 ++ framework/taplo.toml | 8 +- integrations/Cargo.toml | 15 +- integrations/oracles/pyth/Cargo.toml | 26 + integrations/oracles/pyth/src/lib.rs | 90 ++++ integrations/taplo.toml | 6 +- interchain/Cargo.toml | 2 + interchain/modules-clone-testing/Cargo.toml | 7 + .../modules-clone-testing/tests/oracle/mod.rs | 1 + .../tests/oracle/pyth.rs | 10 + .../modules-clone-testing/tests/tests.rs | 1 + interchain/taplo.toml | 6 +- modules/Cargo.toml | 26 +- modules/contracts/adapters/oracle/Cargo.toml | 75 +++ modules/contracts/adapters/oracle/README.md | 79 +++ modules/contracts/adapters/oracle/STATUS.md | 11 + .../adapters/oracle/examples/deploy.rs | 40 ++ .../adapters/oracle/examples/schema.rs | 18 + modules/contracts/adapters/oracle/src/api.rs | 61 +++ .../contracts/adapters/oracle/src/contract.rs | 21 + .../adapters/oracle/src/handlers/execute.rs | 13 + .../oracle/src/handlers/instantiate.rs | 13 + .../adapters/oracle/src/handlers/mod.rs | 7 + .../adapters/oracle/src/handlers/query.rs | 32 ++ modules/contracts/adapters/oracle/src/lib.rs | 90 ++++ .../adapters/oracle/src/oracle_tester.rs | 67 +++ .../adapters/oracle/src/oracles/mod.rs | 19 + .../contracts/adapters/oracle/src/state.rs | 4 + .../adapters/oracle/tests/common/mod.rs | 52 ++ .../adapters/oracle/tests/osmosis.rs | 486 ++++++++++++++++++ .../contracts/adapters/oracle/tests/raw.rs | 172 +++++++ .../contracts/adapters/oracle/tests/swap.rs | 211 ++++++++ modules/taplo.toml | 6 +- taplo.toml | 7 + 41 files changed, 1933 insertions(+), 37 deletions(-) create mode 100644 framework/packages/standards/oracle/Cargo.toml create mode 100644 framework/packages/standards/oracle/README.md create mode 100644 framework/packages/standards/oracle/src/command.rs create mode 100644 framework/packages/standards/oracle/src/error.rs create mode 100644 framework/packages/standards/oracle/src/lib.rs create mode 100644 framework/packages/standards/oracle/src/msg.rs create mode 100644 framework/packages/standards/oracle/src/tests.rs mode change 100644 => 120000 framework/taplo.toml create mode 100644 integrations/oracles/pyth/Cargo.toml create mode 100644 integrations/oracles/pyth/src/lib.rs mode change 100644 => 120000 integrations/taplo.toml create mode 100644 interchain/modules-clone-testing/tests/oracle/mod.rs create mode 100644 interchain/modules-clone-testing/tests/oracle/pyth.rs mode change 100644 => 120000 interchain/taplo.toml create mode 100644 modules/contracts/adapters/oracle/Cargo.toml create mode 100644 modules/contracts/adapters/oracle/README.md create mode 100644 modules/contracts/adapters/oracle/STATUS.md create mode 100644 modules/contracts/adapters/oracle/examples/deploy.rs create mode 100644 modules/contracts/adapters/oracle/examples/schema.rs create mode 100644 modules/contracts/adapters/oracle/src/api.rs create mode 100644 modules/contracts/adapters/oracle/src/contract.rs create mode 100644 modules/contracts/adapters/oracle/src/handlers/execute.rs create mode 100644 modules/contracts/adapters/oracle/src/handlers/instantiate.rs create mode 100644 modules/contracts/adapters/oracle/src/handlers/mod.rs create mode 100644 modules/contracts/adapters/oracle/src/handlers/query.rs create mode 100644 modules/contracts/adapters/oracle/src/lib.rs create mode 100644 modules/contracts/adapters/oracle/src/oracle_tester.rs create mode 100644 modules/contracts/adapters/oracle/src/oracles/mod.rs create mode 100644 modules/contracts/adapters/oracle/src/state.rs create mode 100644 modules/contracts/adapters/oracle/tests/common/mod.rs create mode 100644 modules/contracts/adapters/oracle/tests/osmosis.rs create mode 100644 modules/contracts/adapters/oracle/tests/raw.rs create mode 100644 modules/contracts/adapters/oracle/tests/swap.rs mode change 100644 => 120000 modules/taplo.toml create mode 100644 taplo.toml diff --git a/framework/Cargo.lock b/framework/Cargo.lock index 657eeb1460..9ca31e1f36 100644 --- a/framework/Cargo.lock +++ b/framework/Cargo.lock @@ -461,6 +461,34 @@ dependencies = [ "workspace-hack", ] +[[package]] +name = "abstract-oracle-standard" +version = "0.25.0" +dependencies = [ + "abstract-adapter", + "abstract-adapter-utils", + "abstract-interface", + "abstract-sdk", + "abstract-std", + "abstract-testing", + "anyhow", + "clap", + "cosmwasm-schema", + "cosmwasm-std", + "cw-address-like", + "cw-asset", + "cw-orch 0.27.0", + "cw-storage-plus", + "cw20", + "dotenv", + "env_logger", + "schemars", + "semver", + "serde", + "thiserror", + "workspace-hack", +] + [[package]] name = "abstract-polytone" version = "2.0.0" diff --git a/framework/packages/standards/oracle/Cargo.toml b/framework/packages/standards/oracle/Cargo.toml new file mode 100644 index 0000000000..8d694244c7 --- /dev/null +++ b/framework/packages/standards/oracle/Cargo.toml @@ -0,0 +1,53 @@ +[package] +description = "The oracle adapter is a Abstract adapter for querying oracle prices. It provides a common interface for all oracles" +name = "abstract-oracle-standard" + +authors = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +version = { workspace = true } + +exclude = ["contract.wasm", "hash.txt"] +resolver = "2" + + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +default = ["export"] +export = [] +testing = ["cw-orch/daemon", "abstract-interface/testing"] + +# Keep as is until TendermintStake updates. +[dependencies] +cosmwasm-schema = { workspace = true } +cosmwasm-std = { workspace = true } +cw-address-like = { workspace = true } +cw-asset = { workspace = true } +cw-storage-plus = { workspace = true } +cw20 = { workspace = true } +schemars = { workspace = true } +serde = { workspace = true } +thiserror = { workspace = true } + +abstract-adapter = { version = "0.25.0", path = "../../abstract-adapter" } +abstract-adapter-utils = { workspace = true } +abstract-sdk = { workspace = true } +abstract-std = { workspace = true } +cw-orch = { workspace = true } + +abstract-interface = { version = "0.25.0", path = "../../abstract-interface" } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +workspace-hack = { version = "0.1", path = "../../../workspace-hack" } + +[dev-dependencies] +abstract-interface = { workspace = true, features = ["daemon"] } +abstract-sdk = { workspace = true, features = ["test-utils"] } +abstract-testing = { workspace = true } +anyhow = { workspace = true } +clap = { workspace = true } +dotenv = "0.15.0" +env_logger = "0.11.3" +semver = { workspace = true } diff --git a/framework/packages/standards/oracle/README.md b/framework/packages/standards/oracle/README.md new file mode 100644 index 0000000000..e0b4c3fb6e --- /dev/null +++ b/framework/packages/standards/oracle/README.md @@ -0,0 +1,5 @@ +# Dex Adapter Trait + +A trait that defines a standard interface for Dex interactions. This trait should be implemented for each Dex that the adapter supports. + +To implement this trait, create a new package, import this crate and implement the trait for your Dex. diff --git a/framework/packages/standards/oracle/src/command.rs b/framework/packages/standards/oracle/src/command.rs new file mode 100644 index 0000000000..8665affe41 --- /dev/null +++ b/framework/packages/standards/oracle/src/command.rs @@ -0,0 +1,22 @@ +use abstract_adapter_utils::identity::Identify; +use abstract_sdk::feature_objects::AnsHost; +use cosmwasm_std::{Deps, Env}; + +use crate::error::OracleError; +use crate::msg::{PriceResponse, Seconds}; + +/// # OracleCommand +/// ensures DEX adapters support the expected functionality. +/// +/// Implements the usual DEX operations. +pub trait OracleCommand: Identify { + /// Return oracle price given pair id + fn price( + &self, + deps: Deps, + env: &Env, + ans_host: &AnsHost, + price_id: String, + no_older_than: Seconds, + ) -> Result; +} diff --git a/framework/packages/standards/oracle/src/error.rs b/framework/packages/standards/oracle/src/error.rs new file mode 100644 index 0000000000..7ab9fb43b2 --- /dev/null +++ b/framework/packages/standards/oracle/src/error.rs @@ -0,0 +1,75 @@ +use abstract_adapter::AdapterError; +use abstract_sdk::AbstractSdkError; +use abstract_std::{ + objects::{ans_host::AnsHostError, DexAssetPairing}, + AbstractError, +}; +use cosmwasm_std::StdError; +use cw_asset::AssetError; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum OracleError { + #[error(transparent)] + Std(#[from] StdError), + + #[error(transparent)] + AbstractOs(#[from] AbstractError), + + #[error(transparent)] + AbstractSdk(#[from] AbstractSdkError), + + #[error(transparent)] + Asset(#[from] AssetError), + + #[error(transparent)] + AdapterError(#[from] AdapterError), + + #[error(transparent)] + AnsHostError(#[from] AnsHostError), + + #[error("DEX {0} is not a known dex on this network.")] + UnknownDex(String), + + #[error("DEX {0} is not local to this network.")] + ForeignDex(String), + + #[error("Asset type: {0} is unsupported.")] + UnsupportedAssetType(String), + + #[error("Can't provide liquidity with less than two assets")] + TooFewAssets {}, + + #[error("Can't provide liquidity with more than {0} assets")] + TooManyAssets(u8), + + #[error("Provided asset {0} not in pool with assets {1:?}.")] + ArgumentMismatch(String, Vec), + + #[error("Balancer pool not supported for dex {0}.")] + BalancerNotSupported(String), + + #[error("Pair {0} on DEX {1} does not match with pair address {2}")] + DexMismatch(String, String, String), + + #[error("Not implemented for dex {0}")] + NotImplemented(String), + + #[error("Maximum spread {0} exceeded for dex {1}")] + MaxSlippageAssertion(String, String), + + #[error("Message generation for IBC queries not supported.")] + IbcMsgQuery, + + #[error("Asset pairing {} not found.", asset_pairing)] + AssetPairingNotFound { asset_pairing: DexAssetPairing }, + + #[error("Invalid Generate Message")] + InvalidGenerateMessage, + + #[error("Pool address not specified. You need to specify it when using raw asset addresses or denom")] + PoolAddressEmpty, + + #[error("Only account of abstract namespace can update configuration")] + Unauthorized {}, +} diff --git a/framework/packages/standards/oracle/src/lib.rs b/framework/packages/standards/oracle/src/lib.rs new file mode 100644 index 0000000000..1f4168173e --- /dev/null +++ b/framework/packages/standards/oracle/src/lib.rs @@ -0,0 +1,13 @@ +mod command; +mod error; + +pub mod msg; +#[cfg(feature = "testing")] +pub mod tests; + +// Export interface for use in SDK modules +pub use abstract_adapter_utils::{coins_in_assets, cw_approve_msgs, Identify}; +pub use command::OracleCommand; +pub use error::OracleError; + +pub const ORACLE_ADAPTER_ID: &str = "abstract:oracle"; diff --git a/framework/packages/standards/oracle/src/msg.rs b/framework/packages/standards/oracle/src/msg.rs new file mode 100644 index 0000000000..2896469932 --- /dev/null +++ b/framework/packages/standards/oracle/src/msg.rs @@ -0,0 +1,51 @@ +#![warn(missing_docs)] +//! # Dex Adapter API +// re-export response types +use abstract_std::adapter; +use cosmwasm_schema::QueryResponses; +use cosmwasm_std::{Decimal, Empty}; + +/// The name of the dex to trade on. +pub type OracleName = String; + +/// Top-level Abstract Adapter execute message. This is the message that is passed to the `execute` entrypoint of the smart-contract. +pub type ExecuteMsg = adapter::ExecuteMsg; +/// Top-level Abstract Adapter instantiate message. This is the message that is passed to the `instantiate` entrypoint of the smart-contract. +pub type InstantiateMsg = adapter::InstantiateMsg; +/// Top-level Abstract Adapter query message. This is the message that is passed to the `query` entrypoint of the smart-contract. +pub type QueryMsg = adapter::QueryMsg; + +impl adapter::AdapterQueryMsg for OracleQueryMsg {} + +/// Query messages for the dex adapter +#[cosmwasm_schema::cw_serde] +#[derive(QueryResponses, cw_orch::QueryFns)] +pub enum OracleQueryMsg { + /// Query the oracle adapter config + #[returns(Config)] + Config {}, + /// Query the latest price attached to the price source key + #[returns(PriceResponse)] + Price { + /// Identifier of the oracle value that you wish to query on the oracle + price_source_key: String, + /// Identifier of the oracle + oracle: OracleName, + /// Maximum age of the price + max_age: Seconds, + }, +} + +/// Alias to document time unit the oracle adapter expects data to be in. +pub type Seconds = u64; + +/// Price Response returned by an adapter query +#[cosmwasm_schema::cw_serde] +pub struct PriceResponse { + /// Price response + pub price: Decimal, +} + +/// No Config for this adapter +#[cosmwasm_schema::cw_serde] +pub struct Config {} diff --git a/framework/packages/standards/oracle/src/tests.rs b/framework/packages/standards/oracle/src/tests.rs new file mode 100644 index 0000000000..2db1155e0d --- /dev/null +++ b/framework/packages/standards/oracle/src/tests.rs @@ -0,0 +1,41 @@ +use std::fmt::Debug; + +use crate::msg::PriceResponse; +use cosmwasm_std::StdError; +use cw_orch::daemon::live_mock::mock_dependencies; +use cw_orch::prelude::*; + +use crate::{OracleCommand, OracleError}; + +pub struct OracleCommandTester { + chain: ChainInfoOwned, + adapter: Box, +} + +pub fn expect_eq(t1: T, t2: T) -> Result<(), StdError> { + if t1 != t2 { + Err(StdError::generic_err(format!( + "Test failed, wrong result, expected : {:?}, got : {:?}", + t1, t2 + )))? + } + Ok(()) +} + +impl OracleCommandTester { + pub fn new(chain: ChainInfoOwned, module: T) -> Self { + Self { + chain, + adapter: Box::new(module), + } + } + + pub fn test_query_price(&self, price_source_key: String) -> Result { + let deps = mock_dependencies(self.chain.clone()); + let ans_host = todo!(); + let price_response = self + .adapter + .price(deps.as_ref(), ans_host, price_source_key)?; + Ok(price_response) + } +} diff --git a/framework/taplo.toml b/framework/taplo.toml deleted file mode 100644 index 2c0e2f28cf..0000000000 --- a/framework/taplo.toml +++ /dev/null @@ -1,7 +0,0 @@ -exclude = ["workspace-hack/Cargo.toml"] - -[formatting] -align_entries = true -column_width = 100 -inline_table_expand = false -reorder_keys = true diff --git a/framework/taplo.toml b/framework/taplo.toml new file mode 120000 index 0000000000..68ea0383d0 --- /dev/null +++ b/framework/taplo.toml @@ -0,0 +1 @@ +../taplo.toml \ No newline at end of file diff --git a/integrations/Cargo.toml b/integrations/Cargo.toml index 311deee84e..9849f25f8e 100644 --- a/integrations/Cargo.toml +++ b/integrations/Cargo.toml @@ -7,6 +7,7 @@ members = [ # "wyndex-adapter", # "kujira-adapter", # "mars-adapter", + "oracles/pyth", ] resolver = "2" @@ -60,19 +61,23 @@ abstract-std = { version = "0.25.0" } abstract-adapter-utils = { version = "0.25.0" } abstract-dex-standard = { version = "0.25.0" } abstract-money-market-standard = { version = "0.25.0" } +abstract-oracle-standard = { version = "0.25.0" } abstract-staking-standard = { version = "0.25.0" } # TODO: REMOVE As soon as new dex-standard published [patch.crates-io] -abstract-adapter = { path = "../framework/packages/abstract-adapter" } +abstract-macros = { path = "../framework/packages/abstract-macros" } +abstract-sdk = { path = "../framework/packages/abstract-sdk" } +abstract-std = { path = "../framework/packages/abstract-std" } + +abstract-adapter = { path = "../framework/packages/abstract-adapter" } +abstract-interface = { path = "../framework/packages/abstract-interface" } + abstract-adapter-utils = { path = "../framework/packages/standards/utils" } abstract-dex-standard = { path = "../framework/packages/standards/dex" } -abstract-interface = { path = "../framework/packages/abstract-interface" } -abstract-macros = { path = "../framework/packages/abstract-macros" } abstract-money-market-standard = { path = "../framework/packages/standards/money-market" } -abstract-sdk = { path = "../framework/packages/abstract-sdk" } +abstract-oracle-standard = { path = "../framework/packages/standards/oracle" } abstract-staking-standard = { path = "../framework/packages/standards/staking" } -abstract-std = { path = "../framework/packages/abstract-std" } # In case polytone not released # abstract-polytone = { git = "https://github.com/AbstractSDK/polytone.git", branch = "bump/cw2" } diff --git a/integrations/oracles/pyth/Cargo.toml b/integrations/oracles/pyth/Cargo.toml new file mode 100644 index 0000000000..faf0101d8c --- /dev/null +++ b/integrations/oracles/pyth/Cargo.toml @@ -0,0 +1,26 @@ +[package] +authors = ["Abstract Money "] +description = "Abstract OracleCommand implementation for Pyth" +edition = "2021" +license = "MIT OR Apache-2.0" +name = "abstract-pyth-adapter" +version = "0.26.0" + +[features] +default = ["full_integration"] +full_integration = ["dep:cw20", "dep:cw-asset", "dep:cw-utils", "dep:osmosis-std"] + +[dependencies] +osmosis-std = { version = "0.26.0", optional = true } + +abstract-oracle-standard = { workspace = true } +abstract-sdk = { workspace = true } +abstract-staking-standard = { workspace = true } +cosmwasm-std = { workspace = true, features = ["stargate"] } +cw-asset = { workspace = true, optional = true } +cw-utils = { workspace = true, optional = true } +cw20 = { workspace = true, optional = true } + +cosmwasm-schema = { workspace = true } +# pyth-sdk-cw = "1.2.0" +pyth-sdk-cw = { git = "https://github.com/lvn-hasky-dragon/pyth-crosschain", branch = "update-deps" } diff --git a/integrations/oracles/pyth/src/lib.rs b/integrations/oracles/pyth/src/lib.rs new file mode 100644 index 0000000000..a467941c29 --- /dev/null +++ b/integrations/oracles/pyth/src/lib.rs @@ -0,0 +1,90 @@ +pub const AVAILABLE_CHAINS: &[&str] = &["xion", "xion-testnet"]; +pub const PYTH: &str = "pyth"; +use abstract_oracle_standard::Identify; + +#[derive(Default)] +pub struct Pyth {} + +impl Identify for Pyth { + fn is_available_on(&self, chain_name: &str) -> bool { + AVAILABLE_CHAINS.contains(&chain_name) + } + fn name(&self) -> &'static str { + PYTH + } +} + +#[cfg(feature = "full_integration")] +use { + abstract_oracle_standard::{msg::PriceResponse, OracleCommand, OracleError}, + abstract_sdk::feature_objects::AnsHost, + abstract_sdk::std::objects::ContractEntry, + cosmwasm_std::{Decimal, Deps, Env, StdError}, + pyth_sdk_cw::{query_price_feed, PriceFeedResponse, PriceIdentifier}, +}; + +pub const XION_TEST: &str = "xion1w39ctwxxhxxc2kxarycjxj9rndn65gf8daek7ggarwh3rq3zl0lqqllnmt"; + +#[cfg(feature = "full_integration")] +/// Osmosis app-chain dex implementation +impl OracleCommand for Pyth { + fn price( + &self, + deps: Deps, + env: &Env, + ans_host: &AnsHost, + price_id: String, + no_older_than: u64, + ) -> Result { + let pyth_address = ans_host.query_contract( + &deps.querier, + &ContractEntry { + protocol: PYTH.to_string(), + contract: "oracle".to_string(), + }, + )?; + + // We retrieve the pyth address for the current chain + let price_feed_response: PriceFeedResponse = query_price_feed( + &deps.querier, + pyth_address, + PriceIdentifier::from_hex(price_id.as_bytes()) + .map_err(|e| StdError::generic_err(format!("Wrong price id hex format, {e}")))?, + )?; + let price_feed = price_feed_response.price_feed; + + let current_price = price_feed + .get_price_no_older_than(env.block.time.seconds() as i64, no_older_than) + .ok_or_else(|| StdError::not_found("Current price is not available"))?; + + let power_ten = if current_price.expo < 0 { + Decimal::from_ratio(1u64, 10u64).pow( + (-current_price.expo) + .try_into() + .expect("Wrong power_of_ten logic"), + ) + } else { + Decimal::from_ratio(10u64, 1u64).pow( + current_price + .expo + .try_into() + .expect("Wrong power_of_ten logic"), + ) + }; + + let unsigned_price: u64 = current_price + .price + .try_into() + .expect("Price can't be negative"); + Ok(PriceResponse { + price: power_ten * Decimal::from_ratio(unsigned_price, 1u64), + }) + } +} + +#[cfg(feature = "full_integration")] +impl abstract_sdk::features::ModuleIdentification for Pyth { + fn module_id(&self) -> abstract_sdk::std::objects::module::ModuleId<'static> { + abstract_oracle_standard::ORACLE_ADAPTER_ID + } +} diff --git a/integrations/taplo.toml b/integrations/taplo.toml deleted file mode 100644 index 85e56f12e7..0000000000 --- a/integrations/taplo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[formatting] -align_entries = true -column_width = 100 -inline_table_expand = false -reorder_keys = true diff --git a/integrations/taplo.toml b/integrations/taplo.toml new file mode 120000 index 0000000000..68ea0383d0 --- /dev/null +++ b/integrations/taplo.toml @@ -0,0 +1 @@ +../taplo.toml \ No newline at end of file diff --git a/interchain/Cargo.toml b/interchain/Cargo.toml index 98b9e86bf4..88b465471d 100644 --- a/interchain/Cargo.toml +++ b/interchain/Cargo.toml @@ -80,6 +80,7 @@ challenge-app = { path = "../modules/contracts/apps/challenge" } abstract-cw-staking = { path = "../modules/contracts/adapters/cw-staking" } abstract-dex-adapter = { path = "../modules/contracts/adapters/dex" } abstract-money-market-adapter = { path = "../modules/contracts/adapters/money-market" } +abstract-oracle-adapter = { path = "../modules/contracts/adapters/oracle" } abstract-xion = { package = "account", version = "0.1.0", git = "https://github.com/abstractsdk/xion-contracts", features = ["library"], branch = "fix-for-abstract" } @@ -97,6 +98,7 @@ abstract-dex-standard = { path = "../framework/packages/standards/dex" abstract-interface = { path = "../framework/packages/abstract-interface" } abstract-macros = { path = "../framework/packages/abstract-macros" } abstract-money-market-standard = { path = "../framework/packages/standards/money-market" } +abstract-oracle-standard = { path = "../framework/packages/standards/oracle" } abstract-sdk = { path = "../framework/packages/abstract-sdk" } abstract-staking-standard = { path = "../framework/packages/standards/staking" } abstract-std = { path = "../framework/packages/abstract-std" } diff --git a/interchain/modules-clone-testing/Cargo.toml b/interchain/modules-clone-testing/Cargo.toml index fd5ec21bd4..6ec8930439 100644 --- a/interchain/modules-clone-testing/Cargo.toml +++ b/interchain/modules-clone-testing/Cargo.toml @@ -43,5 +43,12 @@ abstract-money-market-adapter = { workspace = true, features = [ # kujira = { version = "0.8" } astrovault = { version = "0.1.4" } + +abstract-oracle-adapter = { workspace = true, features = [ + "testing", + "pyth", + # "ghost", +] } + serde = "1" serde_json = "1" diff --git a/interchain/modules-clone-testing/tests/oracle/mod.rs b/interchain/modules-clone-testing/tests/oracle/mod.rs new file mode 100644 index 0000000000..8cbcc40452 --- /dev/null +++ b/interchain/modules-clone-testing/tests/oracle/mod.rs @@ -0,0 +1 @@ +pub mod pyth; diff --git a/interchain/modules-clone-testing/tests/oracle/pyth.rs b/interchain/modules-clone-testing/tests/oracle/pyth.rs new file mode 100644 index 0000000000..2598062f15 --- /dev/null +++ b/interchain/modules-clone-testing/tests/oracle/pyth.rs @@ -0,0 +1,10 @@ +pub struct PythOracleTester {} + +impl MockOracle for PythOracleTester {} + +#[test] +fn test_price_query() -> anyhow::Result<()> { + let dex_tester = setup_standard_pool()?; + oracle_tester.test_price()?; + Ok(()) +} diff --git a/interchain/modules-clone-testing/tests/tests.rs b/interchain/modules-clone-testing/tests/tests.rs index 7289e2278c..45151acfe2 100644 --- a/interchain/modules-clone-testing/tests/tests.rs +++ b/interchain/modules-clone-testing/tests/tests.rs @@ -1,3 +1,4 @@ mod dex; mod money_market; +mod oracle; mod staking; diff --git a/interchain/taplo.toml b/interchain/taplo.toml deleted file mode 100644 index 85e56f12e7..0000000000 --- a/interchain/taplo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[formatting] -align_entries = true -column_width = 100 -inline_table_expand = false -reorder_keys = true diff --git a/interchain/taplo.toml b/interchain/taplo.toml new file mode 120000 index 0000000000..68ea0383d0 --- /dev/null +++ b/interchain/taplo.toml @@ -0,0 +1 @@ +../taplo.toml \ No newline at end of file diff --git a/modules/Cargo.toml b/modules/Cargo.toml index 232e132e71..06a199d55a 100644 --- a/modules/Cargo.toml +++ b/modules/Cargo.toml @@ -61,6 +61,7 @@ abstract-testing = { version = "0.25.0" } abstract-adapter-utils = { version = "0.25.0" } abstract-dex-standard = { version = "0.25.0" } abstract-money-market-standard = { version = "0.25.0" } +abstract-oracle-standard = { version = "0.25.0" } abstract-staking-standard = { version = "0.25.0" } # Integrations @@ -86,19 +87,24 @@ rstest = "0.17.0" # this ensures local compatability when compiling locally [patch.crates-io] -abstract-adapter = { path = "../framework/packages/abstract-adapter" } -abstract-adapter-utils = { path = "../framework/packages/standards/utils" } -abstract-app = { path = "../framework/packages/abstract-app" } -abstract-client = { path = "../framework/packages/abstract-client" } +abstract-macros = { path = "../framework/packages/abstract-macros" } +abstract-sdk = { path = "../framework/packages/abstract-sdk" } +abstract-std = { path = "../framework/packages/abstract-std" } + +abstract-client = { path = "../framework/packages/abstract-client" } +abstract-interface = { path = "../framework/packages/abstract-interface" } + +abstract-adapter = { path = "../framework/packages/abstract-adapter" } +abstract-adapter-utils = { path = "../framework/packages/standards/utils" } +abstract-app = { path = "../framework/packages/abstract-app" } +abstract-standalone = { path = "../framework/packages/abstract-standalone" } + abstract-dex-standard = { path = "../framework/packages/standards/dex" } -abstract-interface = { path = "../framework/packages/abstract-interface" } -abstract-macros = { path = "../framework/packages/abstract-macros" } abstract-money-market-standard = { path = "../framework/packages/standards/money-market" } -abstract-sdk = { path = "../framework/packages/abstract-sdk" } +abstract-oracle-standard = { path = "../framework/packages/standards/oracle" } abstract-staking-standard = { path = "../framework/packages/standards/staking" } -abstract-standalone = { path = "../framework/packages/abstract-standalone" } -abstract-std = { path = "../framework/packages/abstract-std" } -abstract-testing = { path = "../framework/packages/abstract-testing" } + +abstract-testing = { path = "../framework/packages/abstract-testing" } # In case polytone not released # abstract-polytone = { git = "https://github.com/AbstractSDK/polytone.git", branch = "bump/cw2" } diff --git a/modules/contracts/adapters/oracle/Cargo.toml b/modules/contracts/adapters/oracle/Cargo.toml new file mode 100644 index 0000000000..2fbfdf8163 --- /dev/null +++ b/modules/contracts/adapters/oracle/Cargo.toml @@ -0,0 +1,75 @@ +[package] +description = "The oracle adapter is an Abstract adapter for querying oracle prices. It provides a common interface for all oracles" +name = "abstract-oracle-adapter" + +authors = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +version = { workspace = true } + +exclude = ["contract.wasm", "hash.txt"] +resolver = "2" + + +[lib] +crate-type = ["cdylib", "rlib"] + +[[example]] +name = "deploy" + +[[example]] +name = "schema" +required-features = ["schema"] + +[features] +default = ["export"] +export = [] +schema = ["abstract-adapter/schema"] +testing = ["dep:abstract-client", "dep:cw20", "dep:serde_json", "abstract-adapter/test-utils"] + +# Supported Oracles +pyth = ["abstract-pyth-adapter/full_integration"] + +# Builds +[package.metadata.optimizer] +builds = [{ name = "pyth", features = ["pyth"] }] + +[dependencies] +abstract-adapter = { workspace = true } +cosmwasm-schema = { workspace = true } +cosmwasm-std = { workspace = true } +cw-asset = { workspace = true } +cw-orch = { workspace = true } +cw-orch-osmosis-test-tube = { workspace = true, optional = true } +cw-storage-plus = { workspace = true } +cw20 = { workspace = true, optional = true } +schemars = { workspace = true } +thiserror = { workspace = true } + +# Local +abstract-adapter-utils = { workspace = true } +abstract-oracle-standard = { workspace = true } + +# Pyth +abstract-pyth-adapter = { path = "../../../../integrations/oracles/pyth", optional = true } + +# Testing # +abstract-client = { workspace = true, optional = true } +serde_json = { version = "1.0", optional = true } + +[dev-dependencies] +abstract-interface = { workspace = true, features = ["daemon"] } +anyhow = { workspace = true } +clap = { workspace = true } +dotenv = "0.15.0" +env_logger = "0.11.3" +semver = { workspace = true } +tokio = { workspace = true } + +bip32 = { version = "0.5.2" } +oracle = { path = ".", features = ["pyth", "testing"], package = "abstract-oracle-adapter" } + + +cw-utils = { workspace = true } +cw20 = { workspace = true } +cw20-base = { workspace = true } diff --git a/modules/contracts/adapters/oracle/README.md b/modules/contracts/adapters/oracle/README.md new file mode 100644 index 0000000000..abbf78bf7d --- /dev/null +++ b/modules/contracts/adapters/oracle/README.md @@ -0,0 +1,79 @@ +# Dex Adapter Module + +The Dex Adapter Module provides a unified interface to interact with various decentralized exchanges (dexes) across the Cosmos ecosystem. By abstracting the differences between various dexes, it allows developers to interact with any dex using a standard interface, streamlining the development process and ensuring compatibility across various dex platforms. + +## Features + +- **Swap**: Exchange one asset for another. +- **Provide Liquidity**: Add assets to a liquidity pool. +- **Withdraw Liquidity**: Remove assets from a liquidity pool. +- **Simulate Swap**: Predict the outcome of a swap without executing it, useful for previewing potential trades. +- **Provide Liquidity Symmetric**: Add an equal value of two assets to a liquidity pool. +- **Custom Swap**: Execute a swap with custom parameters, allowing for more advanced trading strategies. + +```admonish info +Note that each one of these actions supports both ANS and raw variants, meaning that you can use both human-readable and explicit asset denominations. +``` + +## Supported Dexes + +The following Dexes are currently supported: + +- Osmosis (Osmosis) +- Astroport (Neutron, Terra, Injective, Sei) +- Kujira (Kujira) +- Astrovault (Archway) +- Wyndex (Juno) + +If you would like to request support for an additional Dex, please create a GitHub issue or reach out to us on Discord. + +## Installation + +To use the Dex Adapter Module in your Rust project, add the following dependency to your `Cargo.toml`: + +```toml +[dependencies] +abstract-dex-adapter = { git = "https://github.com/AbstractSDK/abstract.git", tag="", default-features = false } +``` + +## Usage with the Abstract SDK + +To interact with a dex, you first need to retrieve the dex using the Dex Adapter. Here's a basic example in Rust: + +```rust +// Retrieve the dex +use abstract_dex_adapter::api::DexInterface; +... + +let dex_name = "osmosis".to_string(); +let offer_asset = OfferAsset::new("juno", 1000u128); +let ask_asset = AssetEntry::new("uusd"); +let max_spread = Some(Decimal::percent(1)); +let belief_price = Some(Decimal::percent(2)); + +let dex = app.dex(deps.as_ref(), dex_name); + +let swap_msg = dex.swap(offer_asset, ask_asset, max_spread, belief_price); +``` + +## Why Use the Dex Adapter? + +### Simplified Development +By using the Dex Adapter, developers can bypass the intricacies of each individual dex. This means less time spent on understanding and integrating with each dex's unique API, and more time focusing on building core functionalities. + +### Flexibility +The Dex Adapter ensures that your application remains flexible. If a new dex emerges or if there are changes to an existing one, your application can easily adapt without undergoing major overhauls. + +### Use Cases +- **Rapid Prototyping**: Quickly build and test applications on top of various dexes without the need for multiple integrations. +- **Cross-Dex Applications**: Build applications that leverage multiple dexes simultaneously, offering users more options and better rates. +- **Future-Proofing**: Ensure your application remains compatible with future dexes that emerge in the Cosmos ecosystem. + +## Documentation + +- **Dex Interface**: For a detailed look at the dex interface, refer to the [Rust trait interface](https://github.com/AbstractSDK/abstract/blob/bcf26f2f446478fd2825de5b187321dc9a626341/modules/contracts/adapters/dex/src/api.rs#L43). +- **Adapters Documentation**: Comprehensive information about adapters can be found in the [official documentation](https://docs.abstract.money/3_framework/6_module_types.html#adapters). + +## Contributing + +If you have suggestions, improvements, new dexes, or want to contribute to the project, we welcome your input on GitHub. diff --git a/modules/contracts/adapters/oracle/STATUS.md b/modules/contracts/adapters/oracle/STATUS.md new file mode 100644 index 0000000000..c258a9e2ad --- /dev/null +++ b/modules/contracts/adapters/oracle/STATUS.md @@ -0,0 +1,11 @@ +# Adapter Status + +This document describes the status of the dex adapter's integrations with different external systems. + +| Protocol | Implementation | Execution Tests | Query Tests | Routing | Notes | +| --- | --- | --- | --- | --- | --- | +| Osmosis | ✅ | ✅ | ❌ | ✅ | | +| Astroport | ✅ | ✅ | ✅ | ✅ | | +| Wynd | ✅ | ✅ | ❌ | ❌ | | +| Bow | ✅ | ❌ | ✅ | ❌ | Liquidity tests not implemented because it uses custom module. | +| Astrovault | ✅ | ✅ | ✅ | ❌ | Testing: Astrovault uses custom archway module to create pool, so we rely on existing pools for testing. | diff --git a/modules/contracts/adapters/oracle/examples/deploy.rs b/modules/contracts/adapters/oracle/examples/deploy.rs new file mode 100644 index 0000000000..dcbf28e628 --- /dev/null +++ b/modules/contracts/adapters/oracle/examples/deploy.rs @@ -0,0 +1,40 @@ +use abstract_interface::{AdapterDeployer, DeployStrategy}; +use abstract_oracle_adapter::interface::OracleAdapter; +use cw_orch::daemon::networks::parse_network; +use cw_orch::prelude::*; +use semver::Version; + +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +fn deploy_oracle(network: ChainInfo) -> anyhow::Result<()> { + let rt = Runtime::new()?; + let version: Version = CONTRACT_VERSION.parse().unwrap(); + let chain = DaemonBuilder::new(network).handle(rt.handle()).build()?; + let oracle = OracleAdapter::new(chain); + oracle.deploy(version, Empty {}, DeployStrategy::Try)?; + Ok(()) +} + +use clap::Parser; +use tokio::runtime::Runtime; + +#[derive(Parser, Default, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + /// Network Id to deploy on + #[arg(short, long)] + network_id: String, +} + +fn main() -> anyhow::Result<()> { + dotenv().ok(); + env_logger::init(); + + use dotenv::dotenv; + + let args = Arguments::parse(); + + let network = parse_network(&args.network_id).unwrap(); + + deploy_oracle(network) +} diff --git a/modules/contracts/adapters/oracle/examples/schema.rs b/modules/contracts/adapters/oracle/examples/schema.rs new file mode 100644 index 0000000000..28517216f9 --- /dev/null +++ b/modules/contracts/adapters/oracle/examples/schema.rs @@ -0,0 +1,18 @@ +use std::{env::current_dir, fs::create_dir_all}; + +use abstract_dex_adapter::{contract::DexAdapter, msg::SimulateSwapResponse}; +use cosmwasm_schema::{export_schema_with_title, remove_schemas, schema_for}; + +fn main() { + let mut out_dir = current_dir().unwrap(); + out_dir.push("schema"); + create_dir_all(&out_dir).unwrap(); + remove_schemas(&out_dir).unwrap(); + + DexAdapter::export_schema(&out_dir); + export_schema_with_title( + &schema_for!(SimulateSwapResponse), + &out_dir, + "AdapterResponse", + ); +} diff --git a/modules/contracts/adapters/oracle/src/api.rs b/modules/contracts/adapters/oracle/src/api.rs new file mode 100644 index 0000000000..47e96dd8d2 --- /dev/null +++ b/modules/contracts/adapters/oracle/src/api.rs @@ -0,0 +1,61 @@ +use crate::ORACLE_ADAPTER_ID; +use abstract_adapter::sdk::{ + features::{AccountIdentification, Dependencies, ModuleIdentification}, + AbstractSdkResult, AdapterInterface, +}; +use abstract_adapter::traits::AbstractNameService; +use abstract_oracle_standard::msg::{OracleName, Seconds}; +use abstract_oracle_standard::msg::{OracleQueryMsg, PriceResponse}; +use cosmwasm_std::Deps; + +// API for Abstract SDK users +/// Interact with the dex adapter in your module. +pub trait OracleInterface: + AccountIdentification + Dependencies + ModuleIdentification + AbstractNameService +{ + /// Construct a new dex interface. + fn oracle<'a>(&'a self, deps: Deps<'a>, name: OracleName) -> Oracle { + Oracle { + base: self, + deps, + name, + } + } +} + +impl + OracleInterface for T +{ +} + +#[derive(Clone)] +pub struct Oracle<'a, T: OracleInterface> { + pub(crate) base: &'a T, + pub(crate) name: OracleName, + pub(crate) deps: Deps<'a>, +} + +impl<'a, T: OracleInterface> Oracle<'a, T> { + /// returns DEX name + pub fn oracle_name(&self) -> OracleName { + self.name.clone() + } + + /// Query a price from the oracle + pub fn price( + &self, + price_source_key: String, + max_age: Seconds, + ) -> AbstractSdkResult { + let adapters = self.base.adapters(self.deps); + + adapters.query( + ORACLE_ADAPTER_ID, + OracleQueryMsg::Price { + price_source_key, + oracle: self.oracle_name(), + max_age, + }, + ) + } +} diff --git a/modules/contracts/adapters/oracle/src/contract.rs b/modules/contracts/adapters/oracle/src/contract.rs new file mode 100644 index 0000000000..f91d1502b3 --- /dev/null +++ b/modules/contracts/adapters/oracle/src/contract.rs @@ -0,0 +1,21 @@ +use abstract_adapter::AdapterContract; +use abstract_oracle_standard::{msg::OracleQueryMsg, OracleError}; +use cosmwasm_std::{Empty, Response}; + +use crate::{handlers, ORACLE_ADAPTER_ID}; + +pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +pub type OracleAdapter = AdapterContract; +pub type OracleResult = Result; + +pub const ORACLE_ADAPTER: OracleAdapter = + OracleAdapter::new(ORACLE_ADAPTER_ID, CONTRACT_VERSION, None) + // .with_instantiate(handlers::instantiate_handler) + // .with_execute(handlers::execute_handler) + .with_query(handlers::query_handler); + +#[cfg(feature = "export")] +use abstract_adapter::export_endpoints; +#[cfg(feature = "export")] +export_endpoints!(ORACLE_ADAPTER, OracleAdapter); diff --git a/modules/contracts/adapters/oracle/src/handlers/execute.rs b/modules/contracts/adapters/oracle/src/handlers/execute.rs new file mode 100644 index 0000000000..65f3ec38af --- /dev/null +++ b/modules/contracts/adapters/oracle/src/handlers/execute.rs @@ -0,0 +1,13 @@ +use cosmwasm_std::{DepsMut, Empty, Env, MessageInfo}; + +use crate::contract::{OracleAdapter, OracleResult}; + +pub fn execute_handler( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _module: OracleAdapter, + _msg: Empty, +) -> OracleResult { + unimplemented!("No execution for this adapter") +} diff --git a/modules/contracts/adapters/oracle/src/handlers/instantiate.rs b/modules/contracts/adapters/oracle/src/handlers/instantiate.rs new file mode 100644 index 0000000000..b0abd41c07 --- /dev/null +++ b/modules/contracts/adapters/oracle/src/handlers/instantiate.rs @@ -0,0 +1,13 @@ +use cosmwasm_std::{DepsMut, Empty, Env, MessageInfo, Response}; + +use crate::contract::{OracleAdapter, OracleResult}; + +pub fn instantiate_handler( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _module: OracleAdapter, + _msg: Empty, +) -> OracleResult { + Ok(Response::default()) +} diff --git a/modules/contracts/adapters/oracle/src/handlers/mod.rs b/modules/contracts/adapters/oracle/src/handlers/mod.rs new file mode 100644 index 0000000000..b28dfdf6fc --- /dev/null +++ b/modules/contracts/adapters/oracle/src/handlers/mod.rs @@ -0,0 +1,7 @@ +mod execute; +mod instantiate; +mod query; + +pub use execute::execute_handler; +pub use instantiate::instantiate_handler; +pub use query::query_handler; diff --git a/modules/contracts/adapters/oracle/src/handlers/query.rs b/modules/contracts/adapters/oracle/src/handlers/query.rs new file mode 100644 index 0000000000..d330a337ef --- /dev/null +++ b/modules/contracts/adapters/oracle/src/handlers/query.rs @@ -0,0 +1,32 @@ +use abstract_adapter::sdk::features::AbstractNameService; + +use abstract_oracle_standard::msg::OracleQueryMsg; +use cosmwasm_std::{to_json_binary, Binary, Deps, Env}; + +use crate::contract::{OracleAdapter, OracleResult}; +use crate::oracles; +use crate::state::CONFIG; + +pub fn query_handler( + deps: Deps, + env: Env, + module: &OracleAdapter, + msg: OracleQueryMsg, +) -> OracleResult { + match msg { + OracleQueryMsg::Config {} => { + to_json_binary(&CONFIG.load(deps.storage)?).map_err(Into::into) + } + OracleQueryMsg::Price { + price_source_key, + oracle, + max_age, + } => { + let oracle = oracles::resolve_oracle(&oracle)?; + let ans = module.name_service(deps); + let price_response = oracle.price(deps, &env, ans.host(), price_source_key, max_age)?; + + to_json_binary(&price_response).map_err(Into::into) + } + } +} diff --git a/modules/contracts/adapters/oracle/src/lib.rs b/modules/contracts/adapters/oracle/src/lib.rs new file mode 100644 index 0000000000..154a4f86fb --- /dev/null +++ b/modules/contracts/adapters/oracle/src/lib.rs @@ -0,0 +1,90 @@ +pub mod api; +pub mod contract; +pub(crate) mod handlers; +pub mod oracles; +pub mod state; +pub mod msg { + pub use abstract_oracle_standard::msg::*; +} +pub use abstract_oracle_standard::ORACLE_ADAPTER_ID; + +// Export interface for use in SDK modules +pub use crate::api::OracleInterface; + +#[cfg(feature = "testing")] +pub mod oracle_tester; + +#[cfg(not(target_arch = "wasm32"))] +pub mod interface { + use crate::{contract::ORACLE_ADAPTER, msg::*}; + use abstract_adapter::abstract_interface::{AdapterDeployer, RegisteredModule}; + use abstract_adapter::objects::dependency::StaticDependency; + use abstract_adapter::sdk::features::ModuleIdentification; + + use abstract_adapter::traits::Dependencies; + use abstract_oracle_standard::ORACLE_ADAPTER_ID; + use cw_orch::{build::BuildPostfix, interface}; + use cw_orch::{contract::Contract, prelude::*}; + + #[interface(InstantiateMsg, ExecuteMsg, QueryMsg, Empty, id=ORACLE_ADAPTER_ID)] + pub struct OracleAdapter; + + // Implement deployer trait + impl AdapterDeployer for OracleAdapter {} + + impl Uploadable for OracleAdapter { + #[cfg(feature = "export")] + fn wrapper() -> ::ContractSource { + Box::new(ContractWrapper::new_with_empty( + crate::contract::execute, + crate::contract::instantiate, + crate::contract::query, + )) + } + fn wasm(chain: &ChainInfoOwned) -> WasmPath { + artifacts_dir_from_workspace!() + .find_wasm_path_with_build_postfix( + "abstract_oracle_adapter", + BuildPostfix::ChainName(chain), + ) + .unwrap() + } + } + + impl RegisteredModule for OracleAdapter { + type InitMsg = Empty; + + fn module_id<'a>() -> &'a str { + ORACLE_ADAPTER.module_id() + } + + fn module_version<'a>() -> &'a str { + ORACLE_ADAPTER.version() + } + + fn dependencies<'a>() -> &'a [StaticDependency] { + ORACLE_ADAPTER.dependencies() + } + } + + impl From> for OracleAdapter { + fn from(contract: Contract) -> Self { + Self(contract) + } + } + + impl + abstract_adapter::abstract_interface::DependencyCreation for OracleAdapter + { + type DependenciesConfig = cosmwasm_std::Empty; + + fn dependency_install_configs( + _configuration: Self::DependenciesConfig, + ) -> Result< + Vec, + abstract_adapter::abstract_interface::AbstractInterfaceError, + > { + Ok(vec![]) + } + } +} diff --git a/modules/contracts/adapters/oracle/src/oracle_tester.rs b/modules/contracts/adapters/oracle/src/oracle_tester.rs new file mode 100644 index 0000000000..7ca28cd551 --- /dev/null +++ b/modules/contracts/adapters/oracle/src/oracle_tester.rs @@ -0,0 +1,67 @@ +use crate::{interface::OracleAdapter, ORACLE_ADAPTER_ID}; +use abstract_adapter::abstract_interface::{AdapterDeployer, DeployStrategy, RegistryExecFns}; +use abstract_adapter::std::objects::module::{ModuleInfo, ModuleVersion}; +use abstract_client::{AbstractClient, Environment}; + +use abstract_oracle_standard::msg::OracleQueryMsgFns; +use cw_orch::{environment::MutCwEnv, prelude::*}; + +use cw_orch::anyhow; + +pub trait MockOracle { + const MAX_AGE: u64; + + /// Name of the dex + fn name(&self) -> String; + + /// First asset + fn price_source_key(&self) -> String; + + /// Ans setup for this oracle + /// For instance, for Pyth, we just register pyth Contract Entry inside ans + fn ans_setup(&self) -> anyhow::Result<()>; +} + +pub struct OracleTester { + pub abstr_deployment: AbstractClient, + pub oracle_adapter: OracleAdapter, + pub oracle: Oracle, +} + +impl OracleTester { + pub fn new(abstr_deployment: AbstractClient, oracle: Oracle) -> anyhow::Result { + // Re-register dex, to make sure it's latest + let _ = abstr_deployment + .registry() + .remove_module(ModuleInfo::from_id( + ORACLE_ADAPTER_ID, + ModuleVersion::Version(crate::contract::CONTRACT_VERSION.to_owned()), + )?); + let oracle_adapter = OracleAdapter::new(abstr_deployment.environment()); + oracle_adapter.deploy( + crate::contract::CONTRACT_VERSION.parse()?, + Empty {}, + DeployStrategy::Force, + )?; + + oracle.ans_setup()?; + + Ok(Self { + abstr_deployment, + oracle_adapter, + oracle, + }) + } + + pub fn test_price(&self) -> anyhow::Result<()> { + // Get the price associated with the ID + let _price = self.oracle_adapter.price( + Oracle::MAX_AGE, + self.oracle.name(), + self.oracle.price_source_key(), + )?; + + // Price should just exist, not using it here + Ok(()) + } +} diff --git a/modules/contracts/adapters/oracle/src/oracles/mod.rs b/modules/contracts/adapters/oracle/src/oracles/mod.rs new file mode 100644 index 0000000000..cdd060a22a --- /dev/null +++ b/modules/contracts/adapters/oracle/src/oracles/mod.rs @@ -0,0 +1,19 @@ +use abstract_oracle_standard::{Identify, OracleCommand, OracleError}; + +/// Any exchange should be identified by the adapter +/// This allows erroring the execution before sending any IBC message to another chain +/// This provides superior UX in case of an IBC execution +pub(crate) fn identify_oracle(value: &str) -> Result, OracleError> { + match value { + abstract_pyth_adapter::PYTH => Ok(Box::::default()), + _ => Err(OracleError::UnknownDex(value.to_owned())), + } +} + +pub(crate) fn resolve_oracle(value: &str) -> Result, OracleError> { + match value { + #[cfg(feature = "pyth")] + abstract_pyth_adapter::PYTH => Ok(Box::::default()), + _ => Err(OracleError::ForeignDex(value.to_owned())), + } +} diff --git a/modules/contracts/adapters/oracle/src/state.rs b/modules/contracts/adapters/oracle/src/state.rs new file mode 100644 index 0000000000..159b9b77be --- /dev/null +++ b/modules/contracts/adapters/oracle/src/state.rs @@ -0,0 +1,4 @@ +use abstract_oracle_standard::msg::Config; +use cw_storage_plus::Item; + +pub const CONFIG: Item = Item::new("config"); diff --git a/modules/contracts/adapters/oracle/tests/common/mod.rs b/modules/contracts/adapters/oracle/tests/common/mod.rs new file mode 100644 index 0000000000..69e1f4ae0c --- /dev/null +++ b/modules/contracts/adapters/oracle/tests/common/mod.rs @@ -0,0 +1,52 @@ +use abstract_adapter::std::objects::gov_type::GovernanceDetails; +use abstract_interface::{AbstractAccount, AccountFactory}; +use cw_orch::{environment::Environment, prelude::*}; +pub fn create_default_account( + factory: &AccountFactory, +) -> anyhow::Result> { + let os = factory.create_default_account(GovernanceDetails::Monarchy { + monarch: Addr::unchecked(factory.environment().sender_addr()).to_string(), + })?; + Ok(os) +} + +// /// Instantiates the dex adapter and registers it with the registry +// #[allow(dead_code)] +// pub fn init_dex_adapter( +// chain: Mock, +// deployment: &Abstract, +// version: Option, +// ) -> anyhow::Result> { +// let mut dex_adapter = DexAdapter::new(EXCHANGE, chain); +// dex_adapter +// .as_instance_mut() +// .set_mock(Box::new(boot_core::ContractWrapper::new_with_empty( +// ::dex::contract::execute, +// ::dex::contract::instantiate, +// ::dex::contract::query, +// ))); +// dex_adapter.upload()?; +// dex_adapter.instantiate( +// &InstantiateMsg::{ +// app: DexInstantiateMsg{ +// swap_fee: Decimal::percent(1), +// recipient_os: 0, +// }, +// base: abstract_adapter::std::adapter::BaseInstantiateMsg { +// ans_host_address: deployment.ans_host.addr_str()?, +// registry_address: deployment.registry.addr_str()?, +// }, +// }, +// None, +// None, +// )?; + +// let version: Version = version +// .unwrap_or_else(|| deployment.version.to_string()) +// .parse()?; + +// deployment +// .registry +// .register_adapters(vec![dex_adapter.as_instance()], &version)?; +// Ok(dex_adapter) +// } diff --git a/modules/contracts/adapters/oracle/tests/osmosis.rs b/modules/contracts/adapters/oracle/tests/osmosis.rs new file mode 100644 index 0000000000..dcce8d301f --- /dev/null +++ b/modules/contracts/adapters/oracle/tests/osmosis.rs @@ -0,0 +1,486 @@ +#![cfg(feature = "osmosis-test")] + +use std::{format, rc::Rc}; + +use abstract_adapter::std::{ + ans_host::ExecuteMsgFns, + objects::{ + gov_type::GovernanceDetails, pool_id::PoolAddressBase, AnsAsset, AssetEntry, PoolMetadata, + }, +}; +use abstract_dex_adapter::{ + contract::CONTRACT_VERSION, + interface::DexAdapter, + msg::{DexInstantiateMsg, SwapNode}, + DEX_ADAPTER_ID, +}; +use abstract_dex_standard::ans_action::DexAnsAction; +use abstract_interface::{ + Abstract, AbstractInterfaceError, AccountI, AdapterDeployer, AnsHost, DeployStrategy, +}; +use abstract_osmosis_adapter::OSMOSIS; +use anyhow::Result as AnyResult; +use cosmwasm_std::{coin, coins, Decimal, Uint128}; +use cw_asset::AssetBase; +use cw_orch::prelude::*; +use cw_orch_osmosis_test_tube::{osmosis_test_tube::Account, OsmosisTestTube}; + +/// Provide liquidity using Abstract's OS (registered in daemon_state). +pub fn provide( + dex_adapter: &DexAdapter, + asset1: (&str, u128), + asset2: (&str, u128), + dex: String, + os: &AccountI, + ans_host: &AnsHost, +) -> Result<(), AbstractInterfaceError> { + let asset_entry1 = AssetEntry::new(asset1.0); + let asset_entry2 = AssetEntry::new(asset2.0); + + dex_adapter.ans_action( + dex, + DexAnsAction::ProvideLiquidity { + assets: vec![ + AnsAsset::new(asset_entry1, asset1.1), + AnsAsset::new(asset_entry2, asset2.1), + ], + max_spread: Some(Decimal::percent(30)), + }, + os, + ans_host, + )?; + Ok(()) +} + +/// Withdraw liquidity using Abstract's OS (registered in daemon_state). +pub fn withdraw( + dex_adapter: &DexAdapter, + lp_token: &str, + amount: impl Into, + dex: String, + os: &AccountI, + ans_host: &AnsHost, +) -> Result<(), AbstractInterfaceError> { + let lp_token = AnsAsset::new(lp_token, amount.into()); + + dex_adapter.ans_action( + dex, + DexAnsAction::WithdrawLiquidity { lp_token }, + os, + ans_host, + )?; + Ok(()) +} + +fn get_pool_token(id: u64) -> String { + format!("gamm/pool/{}", id) +} + +#[allow(clippy::type_complexity)] +fn setup_mock() -> anyhow::Result<( + OsmosisTestTube, + DexAdapter, + AccountI, + Abstract, + u64, +)> { + let atom = "uatom"; + let osmo = "uosmo"; + let juno = "ujunox"; + + let chain = OsmosisTestTube::new(vec![ + coin(1_000_000_000_000, atom), + coin(1_000_000_000_000, juno), + coin(1_000_000_000_000, osmo), + ]); + + let deployment = Abstract::deploy_on(chain.clone(), ())?; + + let _root_os = AccountI::create_default_account( + &deployment, + GovernanceDetails::Monarchy { + monarch: chain.sender_addr().to_string(), + }, + )?; + let dex_adapter = DexAdapter::new(DEX_ADAPTER_ID, chain.clone()); + + dex_adapter.deploy( + CONTRACT_VERSION.parse()?, + DexInstantiateMsg { + swap_fee: Decimal::percent(1), + recipient_account: 0, + }, + DeployStrategy::Try, + )?; + + // We need to register some pairs and assets on the ans host contract + + let pool_id = + chain.create_pool(vec![coin(10_000_000_000, osmo), coin(10_000_000_000, atom)])?; + + deployment + .ans_host + .update_asset_addresses( + vec![ + ("atom".to_string(), cw_asset::AssetInfoBase::native(atom)), + ("osmo".to_string(), cw_asset::AssetInfoBase::native(osmo)), + ( + "osmosis/atom,osmo".to_string(), + cw_asset::AssetInfoBase::native(get_pool_token(pool_id)), + ), + ], + vec![], + ) + .unwrap(); + + deployment + .ans_host + .update_dexes(vec![OSMOSIS.into()], vec![]) + .unwrap(); + + deployment + .ans_host + .update_pools( + vec![( + PoolAddressBase::id(pool_id), + PoolMetadata::constant_product( + OSMOSIS, + vec!["osmo".to_string(), "atom".to_string()], + ), + )], + vec![], + ) + .unwrap(); + + let account = AccountI::create_default_account( + &deployment, + GovernanceDetails::Monarchy { + monarch: chain.sender_addr().to_string(), + }, + )?; + + // install DEX_ADAPTER_ID on OS + account.install_adapter(&dex_adapter, &[])?; + + Ok((chain, dex_adapter, account, deployment, pool_id)) +} + +#[test] +fn swap() -> AnyResult<()> { + // We need to deploy a Testube pool + let (chain, dex_adapter, os, abstr, _pool_id) = setup_mock()?; + + let account_addr = os.address()?; + + let swap_value = 1_000_000_000u128; + + chain.bank_send(account_addr.to_string(), coins(swap_value, "uatom"))?; + + // Before swap, we need to have 0 uosmo and swap_value uatom + let balances = chain.query_all_balances(&account_addr)?; + assert_eq!(balances, coins(swap_value, "uatom")); + // swap 100_000 uatom to uosmo + dex_adapter.ans_swap( + ("atom", swap_value), + "osmo", + OSMOSIS.into(), + &os, + &abstr.ans_host, + )?; + + // Assert balances + let balances = chain.query_all_balances(&account_addr)?; + assert_eq!(balances.len(), 1); + let balance = chain.query_balance(&account_addr, "uosmo")?; + assert!(balance > Uint128::zero()); + + Ok(()) +} + +#[test] +fn swap_concentrated_liquidity() -> AnyResult<()> { + // We need to deploy a Testube pool + let (chain, dex_adapter, os, deployment, _pool_id) = setup_mock()?; + + let account_addr = os.address()?; + + let swap_value = 1_000_000_000u128; + + chain.bank_send(account_addr.to_string(), coins(swap_value, "uatom"))?; + + let lp = "osmosis/osmo2,atom2"; + let pool_id = chain.create_pool(vec![coin(1_000, "uosmo"), coin(1_000, "uatom")])?; + + deployment + .ans_host + .update_asset_addresses( + vec![ + ( + "osmo2".to_string(), + cw_asset::AssetInfoBase::native("uosmo"), + ), + ( + "atom2".to_string(), + cw_asset::AssetInfoBase::native("uatom"), + ), + ( + lp.to_string(), + cw_asset::AssetInfoBase::native(get_pool_token(pool_id)), + ), + ], + vec![], + ) + .unwrap(); + deployment + .ans_host + .update_pools( + vec![( + PoolAddressBase::id(pool_id), + PoolMetadata::concentrated_liquidity( + OSMOSIS, + vec!["osmo2".to_string(), "atom2".to_string()], + ), + )], + vec![], + ) + .unwrap(); + + // Before swap, we need to have 0 uosmo and swap_value uatom + let balances = chain.query_all_balances(&account_addr)?; + assert_eq!(balances, coins(swap_value, "uatom")); + // swap 100_000 uatom to uosmo + dex_adapter.ans_swap( + ("atom2", swap_value), + "osmo2", + OSMOSIS.into(), + &os, + &deployment.ans_host, + )?; + + // Assert balances + let balances = chain.query_all_balances(&account_addr)?; + assert_eq!(balances.len(), 1); + let balance = chain.query_balance(&account_addr, "uosmo")?; + assert!(balance > Uint128::zero()); + + Ok(()) +} + +#[test] +fn provide_liquidity_two_sided() -> AnyResult<()> { + // We need to deploy a Testube pool + let (chain, dex_adapter, os, abstr, pool_id) = setup_mock()?; + + let account_addr = os.address()?; + + let provide_value = 1_000_000_000u128; + + // Before providing, we need to have no assets in the account + let balances = chain.query_all_balances(&account_addr)?; + assert!(balances.is_empty()); + chain.bank_send(account_addr.to_string(), coins(provide_value * 2, "uatom"))?; + chain.bank_send(account_addr.to_string(), coins(provide_value * 2, "uosmo"))?; + + // provide to the pool + provide( + &dex_adapter, + ("atom", provide_value), + ("osmo", provide_value), + OSMOSIS.into(), + &os, + &abstr.ans_host, + )?; + + // provide to the pool reversed + provide( + &dex_adapter, + // reversed denoms + ("osmo", provide_value), + ("atom", provide_value), + OSMOSIS.into(), + &os, + &abstr.ans_host, + )?; + + // After providing, we need to get the liquidity token + let balances = chain.query_all_balances(&account_addr)?; + assert_eq!( + balances, + coins( + 10_000_000_000_000_000_000 + 9_999_999_999_999_999_990, + get_pool_token(pool_id) + ) + ); + + Ok(()) +} + +#[test] +fn provide_liquidity_one_sided() -> AnyResult<()> { + // We need to deploy a Testube pool + let (chain, dex_adapter, os, abstr, pool_id) = setup_mock()?; + + let account_addr = os.address()?; + + let provide_value = 1_000_000_000u128; + + // Before providing, we need to have no assets in the account + let balances = chain.query_all_balances(&account_addr)?; + assert!(balances.is_empty()); + chain.bank_send(account_addr.to_string(), coins(provide_value, "uatom"))?; + chain.bank_send(account_addr.to_string(), coins(provide_value, "uosmo"))?; + + // provide to the pool + provide( + &dex_adapter, + ("atom", provide_value), + ("osmo", 0), + OSMOSIS.into(), + &os, + &abstr.ans_host, + )?; + + // provide to the pool reversed + provide( + &dex_adapter, + // reversed denoms + ("osmo", provide_value), + ("atom", 0), + OSMOSIS.into(), + &os, + &abstr.ans_host, + )?; + + // After providing, we need to get the liquidity token + let balances = chain.query_all_balances(&account_addr)?; + let lp_balance = balances + .iter() + .find(|c| c.denom == get_pool_token(pool_id)) + .unwrap(); + assert!(lp_balance.amount.u128() > 9_000_000_000_000_000_000); + + Ok(()) +} + +#[test] +fn withdraw_liquidity() -> AnyResult<()> { + // We need to deploy a Testube pool + let (chain, dex_adapter, os, abstr, pool_id) = setup_mock()?; + + let account_addr = os.address()?; + + let provide_value = 1_000_000_000u128; + + // Before providing, we need to have no assets in the account + let balances = chain.query_all_balances(&account_addr)?; + assert!(balances.is_empty()); + chain.bank_send(account_addr.to_string(), coins(provide_value, "uatom"))?; + chain.bank_send(account_addr.to_string(), coins(provide_value, "uosmo"))?; + + // provide to the pool + provide( + &dex_adapter, + ("atom", provide_value), + ("osmo", provide_value), + OSMOSIS.into(), + &os, + &abstr.ans_host, + )?; + + // After providing, we need to get the liquidity token + let balance = chain.query_balance(&account_addr, &get_pool_token(pool_id))?; + + // withdraw from the pool + withdraw( + &dex_adapter, + "osmosis/atom,osmo", + balance / Uint128::from(2u128), + OSMOSIS.into(), + &os, + &abstr.ans_host, + )?; + + // After withdrawing, we should get some tokens in return and have some lp token left + let balances = chain.query_all_balances(&account_addr)?; + assert_eq!(balances.len(), 3); + + Ok(()) +} + +#[test] +fn swap_route() -> AnyResult<()> { + // We need to deploy a Testube pool + let (chain, dex_adapter, os, abstr, pool_id_atom_osmo) = setup_mock()?; + let juno = "ujunox"; + let osmo = "uosmo"; + + let pool_id_osmo_juno = + chain.create_pool(vec![coin(10_000_000_000, osmo), coin(10_000_000_000, juno)])?; + + abstr + .ans_host + .update_asset_addresses( + vec![ + ("osmo".to_string(), cw_asset::AssetInfoBase::native(osmo)), + ("juno".to_string(), cw_asset::AssetInfoBase::native(juno)), + ( + "osmosis/osmo,juno".to_string(), + cw_asset::AssetInfoBase::native(get_pool_token(pool_id_osmo_juno)), + ), + ], + vec![], + ) + .unwrap(); + + abstr + .ans_host + .update_pools( + vec![( + PoolAddressBase::id(pool_id_osmo_juno), + PoolMetadata::constant_product( + OSMOSIS, + vec!["osmo".to_string(), "juno".to_string()], + ), + )], + vec![], + ) + .unwrap(); + + let account_addr = os.address()?; + + let swap_value = 1_000_000_000u128; + + chain.bank_send(account_addr.to_string(), coins(swap_value, "uatom"))?; + + // Before swap, we need to have 0 uosmo and swap_value uatom + let balances = chain.query_all_balances(&account_addr)?; + assert_eq!(balances, coins(swap_value, "uatom")); + // swap 100_000 uatom to uosmo + dex_adapter.raw_action( + OSMOSIS.to_string(), + abstract_dex_adapter::msg::DexAction::RouteSwap { + route: vec![ + SwapNode { + pool_id: PoolAddressBase::Id(pool_id_atom_osmo), + ask_asset: cw_asset::AssetInfoBase::Native("uosmo".to_owned()), + }, + SwapNode { + pool_id: PoolAddressBase::Id(pool_id_osmo_juno), + ask_asset: cw_asset::AssetInfoBase::Native(juno.to_owned()), + }, + ], + offer_asset: AssetBase::native("uatom", swap_value), + max_spread: None, + belief_price: None, + }, + &os, + )?; + + // Assert balances + let balances = chain.query_all_balances(&account_addr)?; + assert_eq!(balances.len(), 1); + let balance = chain.query_balance(&account_addr, juno)?; + assert!(balance > Uint128::zero()); + + Ok(()) +} diff --git a/modules/contracts/adapters/oracle/tests/raw.rs b/modules/contracts/adapters/oracle/tests/raw.rs new file mode 100644 index 0000000000..826f21e9b1 --- /dev/null +++ b/modules/contracts/adapters/oracle/tests/raw.rs @@ -0,0 +1,172 @@ +#![cfg(feature = "TODO: replace wyndex_bundle")] + +use abstract_adapter::std::{ + adapter::AdapterRequestMsg, + ans_host::QueryMsgFns as _, + objects::{PoolAddress, ABSTRACT_ACCOUNT_ID}, +}; +use abstract_dex_adapter::{contract::CONTRACT_VERSION, msg::DexInstantiateMsg, DEX_ADAPTER_ID}; +use abstract_dex_standard::msg::DexExecuteMsg; +use abstract_interface::{AdapterDeployer, DeployStrategy}; +use cw20::msg::Cw20ExecuteMsgFns as _; +use cw20_base::msg::QueryMsgFns as _; +use cw_asset::{AssetBase, AssetInfoBase}; +mod common; +use abstract_dex_adapter::interface::DexAdapter; +use abstract_dex_standard::action::DexAction; +use abstract_interface::{Abstract, AbstractAccount}; +use common::create_default_account; +use cosmwasm_std::{coin, Decimal}; +use cw_orch::prelude::*; +use wyndex_bundle::{EUR, USD, WYNDEX as WYNDEX_WITHOUT_CHAIN, WYNDEX_OWNER}; + +const WYNDEX: &str = "cosmos-testnet>wyndex"; + +#[allow(clippy::type_complexity)] +fn setup_mock() -> anyhow::Result<( + MockBech32, + wyndex_bundle::WynDex, + DexAdapter, + AbstractAccount, + Abstract, +)> { + let chain = MockBech32::new("mock"); + let sender = chain.sender_addr(); + let deployment = Abstract::deploy_on(chain.clone(), sender.to_string())?; + let wyndex = wyndex_bundle::WynDex::deploy_on(chain.clone(), Empty {})?; + + let _root_os = create_default_account(&deployment.account_factory)?; + let dex_adapter = DexAdapter::new(DEX_ADAPTER_ID, chain.clone()); + + dex_adapter.deploy( + CONTRACT_VERSION.parse()?, + DexInstantiateMsg { + swap_fee: Decimal::percent(1), + recipient_account: ABSTRACT_ACCOUNT_ID.seq(), + }, + DeployStrategy::Try, + )?; + + let account = create_default_account(&deployment.account_factory)?; + + // mint to account + chain.set_balance(&account.address()?, vec![coin(10_000, EUR)])?; + // install exchange on OS + account.install_adapter(&dex_adapter, None)?; + + Ok((chain, wyndex, dex_adapter, account, deployment)) +} + +#[test] +fn raw_swap_native() -> anyhow::Result<()> { + let (chain, wyndex, dex_adapter, os, abstr) = setup_mock()?; + let account_addr = os.account.address()?; + + let pools = abstr.ans_host.pool_list(None, None, None)?; + println!("{:?}", pools); + + // swap 100 EUR to USD + dex_adapter.raw_swap_native( + (EUR, 100), + USD, + WYNDEX.into(), + &os, + PoolAddress::contract(wyndex.eur_usd_pair).into(), + )?; + + // check balances + let eur_balance = chain.query_balance(&account_addr, EUR)?; + assert_that!(eur_balance.u128()).is_equal_to(9_900); + + let usd_balance = chain.query_balance(&account_addr, USD)?; + assert_that!(usd_balance.u128()).is_equal_to(98); + + // assert that OS 0 received the swap fee + let os0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) + .account + .address()?; + + let os0_eur_balance = chain.query_balance(&os0_account, EUR)?; + + assert_that!(os0_eur_balance.u128()).is_equal_to(1); + + Ok(()) +} + +#[test] +fn raw_swap_native_without_chain() -> anyhow::Result<()> { + let (chain, wyndex, dex_adapter, os, abstr) = setup_mock()?; + let account_addr = os.account.address()?; + + // swap 100 EUR to USD + dex_adapter.raw_swap_native( + (EUR, 100), + USD, + WYNDEX_WITHOUT_CHAIN.into(), + &os, + PoolAddress::contract(wyndex.eur_usd_pair).into(), + )?; + + // check balances + let balances = chain.query_all_balances(&account_addr)?; + println!("{:?}", balances); + let eur_balance = chain.query_balance(&account_addr, EUR)?; + assert_that!(eur_balance.u128()).is_equal_to(9_900); + + let usd_balance = chain.query_balance(&account_addr, USD)?; + assert_that!(usd_balance.u128()).is_equal_to(98); + + // assert that OS 0 received the swap fee + let os0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) + .account + .address()?; + let os0_eur_balance = chain.query_balance(&os0_account, EUR)?; + assert_that!(os0_eur_balance.u128()).is_equal_to(1); + + Ok(()) +} + +#[test] +fn raw_swap_raw() -> anyhow::Result<()> { + let (chain, wyndex, _, os, abstr) = setup_mock()?; + let account_addr = os.account.address()?; + + // transfer raw + let owner = chain.addr_make(WYNDEX_OWNER); + wyndex + .raw_token + .call_as(&owner) + .transfer(10_000u128, account_addr.to_string())?; + + // swap 100 RAW to EUR + let swap_msg = abstract_dex_adapter::msg::ExecuteMsg::Module(AdapterRequestMsg { + account_address: None, + request: DexExecuteMsg::Action { + dex: WYNDEX.to_owned(), + action: DexAction::Swap { + offer_asset: AssetBase::cw20(wyndex.raw_token.address()?.to_string(), 100u128), + ask_asset: AssetInfoBase::native(EUR), + pool: PoolAddress::contract(wyndex.raw_eur_pair).into(), + max_spread: Some(Decimal::percent(30)), + belief_price: None, + }, + }, + }); + os.account.execute_on_module(DEX_ADAPTER_ID, swap_msg)?; + + // check balances + let raw_balance = wyndex.raw_token.balance(account_addr.to_string())?; + assert_that!(raw_balance.balance.u128()).is_equal_to(9_900); + + let eur_balance = chain.query_balance(&account_addr, EUR)?; + assert_that!(eur_balance.u128()).is_equal_to(10098); + + // assert that OS 0 received the swap fee + let account0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) + .account + .address()?; + let os0_raw_balance = wyndex.raw_token.balance(account0_account.to_string())?; + assert_that!(os0_raw_balance.balance.u128()).is_equal_to(1); + + Ok(()) +} diff --git a/modules/contracts/adapters/oracle/tests/swap.rs b/modules/contracts/adapters/oracle/tests/swap.rs new file mode 100644 index 0000000000..318e2f915a --- /dev/null +++ b/modules/contracts/adapters/oracle/tests/swap.rs @@ -0,0 +1,211 @@ +#![cfg(feature = "TODO: replace wyndex_bundle")] + +use abstract_adapter::std::{ans_host::QueryMsgFns as _, objects::ABSTRACT_ACCOUNT_ID}; +use abstract_dex_adapter::{contract::CONTRACT_VERSION, msg::DexInstantiateMsg, DEX_ADAPTER_ID}; +use abstract_dex_standard::{msg::DexFeesResponse, DexError}; +use abstract_interface::{AbstractInterfaceError, AdapterDeployer, DeployStrategy}; +use cw20::msg::Cw20ExecuteMsgFns as _; +use cw20_base::msg::QueryMsgFns as _; +mod common; + +use abstract_dex_adapter::interface::DexAdapter; +use abstract_interface::{Abstract, AbstractAccount}; +use common::create_default_account; +use cosmwasm_std::{coin, Decimal}; +use cw_orch::prelude::*; +use wyndex_bundle::{EUR, RAW_TOKEN, USD, WYNDEX as WYNDEX_WITHOUT_CHAIN, WYNDEX_OWNER}; + +const WYNDEX: &str = "cosmos-testnet>wyndex"; + +#[allow(clippy::type_complexity)] +fn setup_mock() -> anyhow::Result<( + MockBech32, + wyndex_bundle::WynDex, + DexAdapter, + AbstractAccount, + Abstract, +)> { + let chain = MockBech32::new("mock"); + let sender = chain.sender_addr(); + let deployment = Abstract::deploy_on(chain.clone(), sender.to_string())?; + let wyndex = wyndex_bundle::WynDex::deploy_on(chain.clone(), Empty {})?; + + let _root_os = create_default_account(&deployment.account_factory)?; + let dex_adapter = DexAdapter::new(DEX_ADAPTER_ID, chain.clone()); + + dex_adapter.deploy( + CONTRACT_VERSION.parse()?, + DexInstantiateMsg { + swap_fee: Decimal::percent(1), + recipient_account: ABSTRACT_ACCOUNT_ID.seq(), + }, + DeployStrategy::Try, + )?; + + let account = create_default_account(&deployment.account_factory)?; + + // mint to account + chain.set_balance(&account.address()?, vec![coin(10_000, EUR)])?; + // install exchange on OS + account.install_adapter(&dex_adapter, None)?; + + Ok((chain, wyndex, dex_adapter, account, deployment)) +} + +#[test] +fn swap_native() -> anyhow::Result<()> { + let (chain, _, dex_adapter, os, abstr) = setup_mock()?; + let account_addr = os.account.address()?; + + let pools = abstr.ans_host.pool_list(None, None, None)?; + println!("{:?}", pools); + + // swap 100 EUR to USD + dex_adapter.ans_swap((EUR, 100), USD, WYNDEX.into(), &os, &abstr.ans_host)?; + + // check balances + let eur_balance = chain.query_balance(&account_addr, EUR)?; + assert_that!(eur_balance.u128()).is_equal_to(9_900); + + let usd_balance = chain.query_balance(&account_addr, USD)?; + assert_that!(usd_balance.u128()).is_equal_to(98); + + // assert that OS 0 received the swap fee + let os0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) + .account + .address()?; + + let os0_eur_balance = chain.query_balance(&os0_account, EUR)?; + + assert_that!(os0_eur_balance.u128()).is_equal_to(1); + + Ok(()) +} + +#[test] +fn swap_native_without_chain() -> anyhow::Result<()> { + let (chain, _, dex_adapter, os, abstr) = setup_mock()?; + let account_addr = os.account.address()?; + + // swap 100 EUR to USD + dex_adapter.ans_swap( + (EUR, 100), + USD, + WYNDEX_WITHOUT_CHAIN.into(), + &os, + &abstr.ans_host, + )?; + + // check balances + let eur_balance = chain.query_balance(&account_addr, EUR)?; + assert_that!(eur_balance.u128()).is_equal_to(9_900); + + let usd_balance = chain.query_balance(&account_addr, USD)?; + assert_that!(usd_balance.u128()).is_equal_to(98); + + // assert that OS 0 received the swap fee + let os0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) + .account + .address()?; + let os0_eur_balance = chain.query_balance(&os0_account, EUR)?; + assert_that!(os0_eur_balance.u128()).is_equal_to(1); + + Ok(()) +} + +#[test] +fn swap_raw() -> anyhow::Result<()> { + let (chain, wyndex, dex_adapter, os, abstr) = setup_mock()?; + let account_addr = os.account.address()?; + + // transfer raw + let owner = chain.addr_make(WYNDEX_OWNER); + wyndex + .raw_token + .call_as(&owner) + .transfer(10_000u128, account_addr.to_string())?; + + // swap 100 RAW to EUR + dex_adapter.ans_swap((RAW_TOKEN, 100), EUR, WYNDEX.into(), &os, &abstr.ans_host)?; + + // check balances + let raw_balance = wyndex.raw_token.balance(account_addr.to_string())?; + assert_that!(raw_balance.balance.u128()).is_equal_to(9_900); + + let eur_balance = chain.query_balance(&account_addr, EUR)?; + assert_that!(eur_balance.u128()).is_equal_to(10098); + + // assert that OS 0 received the swap fee + let account0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) + .account + .address()?; + let os0_raw_balance = wyndex.raw_token.balance(account0_account.to_string())?; + assert_that!(os0_raw_balance.balance.u128()).is_equal_to(1); + + Ok(()) +} + +#[test] +fn get_fees() -> anyhow::Result<()> { + let (_, _, dex_adapter, _, abstr) = setup_mock()?; + let account0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) + .account + .address()?; + + use abstract_dex_adapter::msg::DexQueryMsgFns as _; + + let fees: DexFeesResponse = dex_adapter.fees()?; + assert_eq!(fees.swap_fee.share(), Decimal::percent(1)); + assert_eq!(fees.recipient, account0_account); + Ok(()) +} + +#[test] +fn authorized_update_fee() -> anyhow::Result<()> { + let (_, _, dex_adapter, _, abstr) = setup_mock()?; + let account0 = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID); + + let update_fee_msg = abstract_dex_standard::msg::ExecuteMsg::Module( + abstract_adapter::std::adapter::AdapterRequestMsg { + account_address: Some(account0.account.addr_str()?), + request: abstract_dex_standard::msg::DexExecuteMsg::UpdateFee { + swap_fee: Some(Decimal::percent(5)), + recipient_account: None, + }, + }, + ); + + dex_adapter.execute(&update_fee_msg, None)?; + + use abstract_dex_adapter::msg::DexQueryMsgFns as _; + + let fees: DexFeesResponse = dex_adapter.fees()?; + assert_eq!(fees.swap_fee.share(), Decimal::percent(5)); + Ok(()) +} + +#[test] +fn unauthorized_update_fee() -> anyhow::Result<()> { + let (_, _, _, account, _) = setup_mock()?; + + let update_fee_msg = abstract_dex_standard::msg::ExecuteMsg::Module( + abstract_adapter::std::adapter::AdapterRequestMsg { + account_address: None, + request: abstract_dex_standard::msg::DexExecuteMsg::UpdateFee { + swap_fee: Some(Decimal::percent(5)), + recipient_account: None, + }, + }, + ); + + let err = account + .account + .execute_on_module(DEX_ADAPTER_ID, update_fee_msg) + .unwrap_err(); + let AbstractInterfaceError::Orch(orch_error) = err else { + panic!("unexpected error type"); + }; + let dex_err: DexError = orch_error.downcast().unwrap(); + assert_eq!(dex_err, DexError::Unauthorized {}); + Ok(()) +} diff --git a/modules/taplo.toml b/modules/taplo.toml deleted file mode 100644 index 85e56f12e7..0000000000 --- a/modules/taplo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[formatting] -align_entries = true -column_width = 100 -inline_table_expand = false -reorder_keys = true diff --git a/modules/taplo.toml b/modules/taplo.toml new file mode 120000 index 0000000000..68ea0383d0 --- /dev/null +++ b/modules/taplo.toml @@ -0,0 +1 @@ +../taplo.toml \ No newline at end of file diff --git a/taplo.toml b/taplo.toml new file mode 100644 index 0000000000..cdbf2861f8 --- /dev/null +++ b/taplo.toml @@ -0,0 +1,7 @@ +exclude = ["workspace-hack/Cargo.toml"] + +[formatting] +align_entries = true +column_width = 100 +inline_table_expand = false +reorder_keys = true From 49d4edf1e4f863904f37fa88434e5a790216f551 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Mon, 25 Nov 2024 11:12:48 +0000 Subject: [PATCH 02/21] Added pyth oracle tests --- interchain/modules-clone-testing/Cargo.toml | 6 + .../tests/oracle/pyth.rs | 130 +++++++++++++++++- .../adapters/oracle/src/oracle_tester.rs | 35 ++--- .../adapters/oracle/src/oracles/mod.rs | 2 + 4 files changed, 153 insertions(+), 20 deletions(-) diff --git a/interchain/modules-clone-testing/Cargo.toml b/interchain/modules-clone-testing/Cargo.toml index 6ec8930439..1f8221ee4f 100644 --- a/interchain/modules-clone-testing/Cargo.toml +++ b/interchain/modules-clone-testing/Cargo.toml @@ -50,5 +50,11 @@ abstract-oracle-adapter = { workspace = true, features = [ # "ghost", ] } +# Pyth sdk +# pyth-sdk-cw = "1.2.0" +pyth-sdk-cw = { git = "https://github.com/lvn-hasky-dragon/pyth-crosschain", branch = "update-deps" } + +hex = "0.4.3" +reqwest = { version = "0.12.9", features = ["blocking"] } serde = "1" serde_json = "1" diff --git a/interchain/modules-clone-testing/tests/oracle/pyth.rs b/interchain/modules-clone-testing/tests/oracle/pyth.rs index 2598062f15..c79ea8edc0 100644 --- a/interchain/modules-clone-testing/tests/oracle/pyth.rs +++ b/interchain/modules-clone-testing/tests/oracle/pyth.rs @@ -1,10 +1,132 @@ -pub struct PythOracleTester {} +use std::str::FromStr; -impl MockOracle for PythOracleTester {} +use abstract_app::{objects::UncheckedContractEntry, std::ans_host::QueryMsgFns}; +use abstract_client::AbstractClient; +use abstract_interface::ExecuteMsgFns; +use abstract_oracle_adapter::{ + oracle_tester::{MockOracle, OracleTester}, + oracles::PYTH, +}; +use cosmwasm_std::{Addr, Binary, Uint128}; +use cw_orch::daemon::networks::XION_TESTNET_1; +use cw_orch::prelude::*; +use cw_orch_clone_testing::CloneTesting; +use pyth_api::PythApiResponse; + +pub const PYTH_XION_ADDRESS: &str = + "xion1w39ctwxxhxxc2kxarycjxj9rndn65gf8daek7ggarwh3rq3zl0lqqllnmt"; + +// Use https://hermes.pyth.network/docs/#/rest/latest_price_updates to query latest update +pub const ORACLE_PRICE_API: &str = "https://hermes.pyth.network/v2/updates/price/latest?ids%5B%5D="; +pub const PRICE_SOURCE_KEY: &str = + "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"; + +pub mod pyth_api { + use serde::{Deserialize, Serialize}; + + #[derive(Serialize, Deserialize)] + pub struct PythApiResponse { + pub binary: PythApiResponseBinary, + pub parsed: Vec, + } + + #[derive(Serialize, Deserialize)] + pub struct PythApiResponseBinary { + pub data: Vec, + } + #[derive(Serialize, Deserialize)] + pub struct PythApiResponseparsed { + pub price: PythApiResponsePrice, + } + #[derive(Serialize, Deserialize)] + pub struct PythApiResponsePrice { + pub price: String, + } +} + +pub struct PythOracleTester { + pub current_oracle_price_data: PythApiResponse, + pub chain: CloneTesting, +} + +impl MockOracle for PythOracleTester { + const MAX_AGE: u64 = 60; + fn price_source_key(&self) -> String { + PRICE_SOURCE_KEY.to_string() + } + + fn name(&self) -> String { + PYTH.to_string() + } + + fn ans_setup(&self, abstr_deployment: &AbstractClient) -> anyhow::Result<()> { + abstr_deployment.name_service().update_contract_addresses( + vec![( + UncheckedContractEntry { + protocol: PYTH.to_string(), + contract: "oracle".to_string(), + }, + PYTH_XION_ADDRESS.to_string(), + )], + vec![], + )?; + Ok(()) + } +} + +fn setup_clone_testing() -> anyhow::Result> { + let clone_testing = CloneTesting::new(XION_TESTNET_1)?; + let pyth_addr = Addr::unchecked(PYTH_XION_ADDRESS); + + let price_data: PythApiResponse = + reqwest::blocking::get(format!("{}{}", ORACLE_PRICE_API, PRICE_SOURCE_KEY))?.json()?; + + let update_data: Vec = price_data + .binary + .data + .iter() + .map(|d| Binary::new(hex::decode(d).unwrap())) + .collect(); + + // We send an update to the oracle contract (no update for now) + let update_fee: Coin = clone_testing.query( + &pyth_sdk_cw::QueryMsg::GetUpdateFee { + vaas: update_data.clone(), + }, + &pyth_addr, + )?; + clone_testing.add_balance(&clone_testing.sender, vec![update_fee.clone()])?; + clone_testing.execute( + &pyth_sdk_cw::ExecuteMsg::UpdatePriceFeeds { + data: update_data.clone(), + }, + &[update_fee], + &pyth_addr, + )?; + + let abstr_deployment = AbstractClient::new(clone_testing.clone())?; + let abstract_admin = abstr_deployment.name_service().ownership()?.owner.unwrap(); + let abstr_deployment = abstr_deployment.call_as(&Addr::unchecked(abstract_admin)); + + let tester = PythOracleTester { + chain: clone_testing, + current_oracle_price_data: price_data, + }; + OracleTester::new(abstr_deployment, tester) +} #[test] fn test_price_query() -> anyhow::Result<()> { - let dex_tester = setup_standard_pool()?; - oracle_tester.test_price()?; + let oracle_tester = setup_clone_testing()?; + let current_price = oracle_tester.test_price()?; + + let raw_price = oracle_tester.oracle.current_oracle_price_data.parsed[0] + .price + .price + .clone(); + // We assume this price has 8 decimals + let price = Uint128::from_str(&raw_price)? / Uint128::from(100_000_000u128); + assert_eq!(current_price.price.to_uint_floor(), price); + Ok(()) } diff --git a/modules/contracts/adapters/oracle/src/oracle_tester.rs b/modules/contracts/adapters/oracle/src/oracle_tester.rs index 7ca28cd551..7ce32252c4 100644 --- a/modules/contracts/adapters/oracle/src/oracle_tester.rs +++ b/modules/contracts/adapters/oracle/src/oracle_tester.rs @@ -1,14 +1,17 @@ use crate::{interface::OracleAdapter, ORACLE_ADAPTER_ID}; -use abstract_adapter::abstract_interface::{AdapterDeployer, DeployStrategy, RegistryExecFns}; +use abstract_adapter::abstract_interface::{ + AdapterDeployer, DeployStrategy, MFactoryQueryFns, RegistryExecFns, +}; +use abstract_adapter::std::ans_host::QueryMsgFns; use abstract_adapter::std::objects::module::{ModuleInfo, ModuleVersion}; use abstract_client::{AbstractClient, Environment}; -use abstract_oracle_standard::msg::OracleQueryMsgFns; +use abstract_oracle_standard::msg::{OracleQueryMsgFns, PriceResponse}; use cw_orch::{environment::MutCwEnv, prelude::*}; use cw_orch::anyhow; -pub trait MockOracle { +pub trait MockOracle { const MAX_AGE: u64; /// Name of the dex @@ -19,16 +22,16 @@ pub trait MockOracle { /// Ans setup for this oracle /// For instance, for Pyth, we just register pyth Contract Entry inside ans - fn ans_setup(&self) -> anyhow::Result<()>; + fn ans_setup(&self, abstr_deployment: &AbstractClient) -> anyhow::Result<()>; } -pub struct OracleTester { +pub struct OracleTester> { pub abstr_deployment: AbstractClient, pub oracle_adapter: OracleAdapter, pub oracle: Oracle, } -impl OracleTester { +impl> OracleTester { pub fn new(abstr_deployment: AbstractClient, oracle: Oracle) -> anyhow::Result { // Re-register dex, to make sure it's latest let _ = abstr_deployment @@ -37,6 +40,7 @@ impl OracleTester { ORACLE_ADAPTER_ID, ModuleVersion::Version(crate::contract::CONTRACT_VERSION.to_owned()), )?); + let oracle_adapter = OracleAdapter::new(abstr_deployment.environment()); oracle_adapter.deploy( crate::contract::CONTRACT_VERSION.parse()?, @@ -44,7 +48,7 @@ impl OracleTester { DeployStrategy::Force, )?; - oracle.ans_setup()?; + oracle.ans_setup(&abstr_deployment)?; Ok(Self { abstr_deployment, @@ -53,15 +57,14 @@ impl OracleTester { }) } - pub fn test_price(&self) -> anyhow::Result<()> { + pub fn test_price(&self) -> anyhow::Result { // Get the price associated with the ID - let _price = self.oracle_adapter.price( - Oracle::MAX_AGE, - self.oracle.name(), - self.oracle.price_source_key(), - )?; - - // Price should just exist, not using it here - Ok(()) + self.oracle_adapter + .price( + Oracle::MAX_AGE, + self.oracle.name(), + self.oracle.price_source_key(), + ) + .map_err(Into::into) } } diff --git a/modules/contracts/adapters/oracle/src/oracles/mod.rs b/modules/contracts/adapters/oracle/src/oracles/mod.rs index cdd060a22a..ea26142127 100644 --- a/modules/contracts/adapters/oracle/src/oracles/mod.rs +++ b/modules/contracts/adapters/oracle/src/oracles/mod.rs @@ -1,5 +1,7 @@ use abstract_oracle_standard::{Identify, OracleCommand, OracleError}; +pub use abstract_pyth_adapter::PYTH; + /// Any exchange should be identified by the adapter /// This allows erroring the execution before sending any IBC message to another chain /// This provides superior UX in case of an IBC execution From c5deb17be52ec2511b15a89373b3cd70ab3bcfa3 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Mon, 25 Nov 2024 13:01:39 +0000 Subject: [PATCH 03/21] Doc and builds --- integrations/oracles/pyth/README.md | 10 ++++++++++ modules/contracts/adapters/oracle/Cargo.toml | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 integrations/oracles/pyth/README.md diff --git a/integrations/oracles/pyth/README.md b/integrations/oracles/pyth/README.md new file mode 100644 index 0000000000..dd716ccbac --- /dev/null +++ b/integrations/oracles/pyth/README.md @@ -0,0 +1,10 @@ +Pyth oracle is available on the following chains: + +Xion Testnet +Neutron Testnet +Osmosis Mainnet +Neutron Mainnet +Osmosis Mainnet + + +The available pariss can bd found under this link: https://www.pyth.network/developers/price-feed-ids#stable \ No newline at end of file diff --git a/modules/contracts/adapters/oracle/Cargo.toml b/modules/contracts/adapters/oracle/Cargo.toml index 2fbfdf8163..e037f92905 100644 --- a/modules/contracts/adapters/oracle/Cargo.toml +++ b/modules/contracts/adapters/oracle/Cargo.toml @@ -32,7 +32,11 @@ pyth = ["abstract-pyth-adapter/full_integration"] # Builds [package.metadata.optimizer] -builds = [{ name = "pyth", features = ["pyth"] }] +builds = [ + { name = "xion", features = ["pyth"] }, + { name = "neutron", features = ["pyth"] }, + { name = "osmosis", features = ["pyth"] }, +] [dependencies] abstract-adapter = { workspace = true } From 981f0ee464aef9a7a180f1b30720d4ae0e9e980e Mon Sep 17 00:00:00 2001 From: Kayanski Date: Tue, 26 Nov 2024 13:06:36 +0000 Subject: [PATCH 04/21] Added documentation and deployment and tests --- .../oracle/{pyth.rs => pyth/integration.rs} | 80 ++++++------ .../tests/oracle/pyth/live.rs | 119 ++++++++++++++++++ .../tests/oracle/pyth/mod.rs | 32 +++++ interchain/scripts/state.json | 6 + .../abstract_cw_staking-archway.wasm | Bin 703209 -> 703209 bytes .../abstract_cw_staking-osmosis.wasm | Bin 720168 -> 720168 bytes modules/artifacts/abstract_cw_staking.wasm | Bin 615547 -> 615547 bytes .../abstract_dex_adapter-archway.wasm | Bin 807659 -> 807659 bytes .../abstract_dex_adapter-osmosis.wasm | Bin 993698 -> 993698 bytes modules/artifacts/abstract_dex_adapter.wasm | Bin 660871 -> 660871 bytes .../abstract_money_market_adapter.wasm | Bin 667693 -> 667690 bytes modules/artifacts/abstract_subscription.wasm | Bin 488102 -> 488102 bytes .../abstract_tendermint_staking_adapter.wasm | Bin 559932 -> 559933 bytes modules/artifacts/calendar_app.wasm | Bin 544446 -> 544446 bytes modules/artifacts/challenge_app.wasm | Bin 709536 -> 709536 bytes modules/artifacts/checksums.txt | 32 ++--- modules/artifacts/my_standalone.wasm | Bin 516465 -> 516469 bytes modules/artifacts/payment_app.wasm | Bin 550440 -> 550440 bytes modules/artifacts/ping_pong.wasm | Bin 547065 -> 547065 bytes modules/contracts/adapters/oracle/Cargo.toml | 82 +++++++----- modules/contracts/adapters/oracle/README.md | 81 ++++++------ .../adapters/oracle/examples/deploy.rs | 36 +++--- .../adapters/oracle/examples/register_ans.rs | 51 ++++++++ .../adapters/oracle/examples/schema.rs | 9 +- .../contracts/adapters/oracle/src/contract.rs | 4 +- modules/contracts/adapters/oracle/src/lib.rs | 31 +++++ .../adapters/oracle/src/oracle_tester.rs | 22 +++- .../adapters/oracle/src/oracles/mod.rs | 12 +- modules/justfile | 2 +- scripts/wasm-all.sh | 20 +-- 30 files changed, 438 insertions(+), 181 deletions(-) rename interchain/modules-clone-testing/tests/oracle/{pyth.rs => pyth/integration.rs} (64%) create mode 100644 interchain/modules-clone-testing/tests/oracle/pyth/live.rs create mode 100644 interchain/modules-clone-testing/tests/oracle/pyth/mod.rs create mode 100644 modules/contracts/adapters/oracle/examples/register_ans.rs diff --git a/interchain/modules-clone-testing/tests/oracle/pyth.rs b/interchain/modules-clone-testing/tests/oracle/pyth/integration.rs similarity index 64% rename from interchain/modules-clone-testing/tests/oracle/pyth.rs rename to interchain/modules-clone-testing/tests/oracle/pyth/integration.rs index c79ea8edc0..ab8cf30b4b 100644 --- a/interchain/modules-clone-testing/tests/oracle/pyth.rs +++ b/interchain/modules-clone-testing/tests/oracle/pyth/integration.rs @@ -1,8 +1,10 @@ use std::str::FromStr; +use super::pyth_api::PythApiResponse; use abstract_app::{objects::UncheckedContractEntry, std::ans_host::QueryMsgFns}; use abstract_client::AbstractClient; use abstract_interface::ExecuteMsgFns; +use abstract_oracle_adapter::interface::deployment::pyth_addresses; use abstract_oracle_adapter::{ oracle_tester::{MockOracle, OracleTester}, oracles::PYTH, @@ -11,42 +13,13 @@ use cosmwasm_std::{Addr, Binary, Uint128}; use cw_orch::daemon::networks::XION_TESTNET_1; use cw_orch::prelude::*; use cw_orch_clone_testing::CloneTesting; -use pyth_api::PythApiResponse; +use networks::{NEUTRON_1, OSMOSIS_1, OSMO_5, PION_1}; -pub const PYTH_XION_ADDRESS: &str = - "xion1w39ctwxxhxxc2kxarycjxj9rndn65gf8daek7ggarwh3rq3zl0lqqllnmt"; - -// Use https://hermes.pyth.network/docs/#/rest/latest_price_updates to query latest update -pub const ORACLE_PRICE_API: &str = "https://hermes.pyth.network/v2/updates/price/latest?ids%5B%5D="; -pub const PRICE_SOURCE_KEY: &str = - "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"; - -pub mod pyth_api { - use serde::{Deserialize, Serialize}; - - #[derive(Serialize, Deserialize)] - pub struct PythApiResponse { - pub binary: PythApiResponseBinary, - pub parsed: Vec, - } - - #[derive(Serialize, Deserialize)] - pub struct PythApiResponseBinary { - pub data: Vec, - } - #[derive(Serialize, Deserialize)] - pub struct PythApiResponseparsed { - pub price: PythApiResponsePrice, - } - #[derive(Serialize, Deserialize)] - pub struct PythApiResponsePrice { - pub price: String, - } -} +pub use super::{ORACLE_PRICE_API, PRICE_SOURCE_KEY}; pub struct PythOracleTester { pub current_oracle_price_data: PythApiResponse, - pub chain: CloneTesting, + pub pyth_address: Addr, } impl MockOracle for PythOracleTester { @@ -66,7 +39,7 @@ impl MockOracle for PythOracleTester { protocol: PYTH.to_string(), contract: "oracle".to_string(), }, - PYTH_XION_ADDRESS.to_string(), + self.pyth_address.to_string(), )], vec![], )?; @@ -74,9 +47,12 @@ impl MockOracle for PythOracleTester { } } -fn setup_clone_testing() -> anyhow::Result> { - let clone_testing = CloneTesting::new(XION_TESTNET_1)?; - let pyth_addr = Addr::unchecked(PYTH_XION_ADDRESS); +fn setup_clone_testing( + chain: ChainInfo, +) -> anyhow::Result> { + let clone_testing = CloneTesting::new(chain.clone())?; + + let pyth_address = pyth_addresses().get(chain.chain_id).unwrap().clone(); let price_data: PythApiResponse = reqwest::blocking::get(format!("{}{}", ORACLE_PRICE_API, PRICE_SOURCE_KEY))?.json()?; @@ -93,7 +69,7 @@ fn setup_clone_testing() -> anyhow::Result anyhow::Result anyhow::Result anyhow::Result<()> { - let oracle_tester = setup_clone_testing()?; +fn test_price_query(chain: ChainInfo) -> anyhow::Result<()> { + let oracle_tester = setup_clone_testing(chain)?; let current_price = oracle_tester.test_price()?; let raw_price = oracle_tester.oracle.current_oracle_price_data.parsed[0] @@ -130,3 +105,24 @@ fn test_price_query() -> anyhow::Result<()> { Ok(()) } + +#[test] +fn test_xion() { + test_price_query(XION_TESTNET_1).unwrap(); +} +#[test] +fn test_osmo_test() { + test_price_query(OSMO_5).unwrap(); +} +#[test] +fn test_pion() { + test_price_query(PION_1).unwrap(); +} +#[test] +fn test_osmosis() { + test_price_query(OSMOSIS_1).unwrap(); +} +#[test] +fn test_neutron() { + test_price_query(NEUTRON_1).unwrap(); +} diff --git a/interchain/modules-clone-testing/tests/oracle/pyth/live.rs b/interchain/modules-clone-testing/tests/oracle/pyth/live.rs new file mode 100644 index 0000000000..4595e6f2a1 --- /dev/null +++ b/interchain/modules-clone-testing/tests/oracle/pyth/live.rs @@ -0,0 +1,119 @@ +use std::str::FromStr; + +use super::pyth_api::PythApiResponse; +use abstract_app::{objects::ContractEntry, std::ans_host::QueryMsgFns}; +use abstract_client::AbstractClient; +use abstract_oracle_adapter::{ + oracle_tester::{MockOracle, OracleTester}, + oracles::PYTH, +}; +use cosmwasm_std::{Binary, Uint128}; +use cw_orch::daemon::networks::XION_TESTNET_1; +use cw_orch::prelude::*; +use cw_orch_clone_testing::CloneTesting; +use networks::{NEUTRON_1, OSMOSIS_1, OSMO_5, PION_1}; + +pub use super::{ORACLE_PRICE_API, PRICE_SOURCE_KEY}; + +pub struct PythOracleTester { + pub current_oracle_price_data: PythApiResponse, +} + +impl MockOracle for PythOracleTester { + const MAX_AGE: u64 = 60; + fn price_source_key(&self) -> String { + PRICE_SOURCE_KEY.to_string() + } + + fn name(&self) -> String { + PYTH.to_string() + } + + fn ans_setup(&self, _abstr_deployment: &AbstractClient) -> anyhow::Result<()> { + Ok(()) + } +} + +fn setup_clone_testing( + chain: ChainInfo, +) -> anyhow::Result> { + let clone_testing = CloneTesting::new(chain.clone())?; + let abstr_deployment = AbstractClient::new(clone_testing.clone())?; + + let pyth_address = abstr_deployment + .name_service() + .contracts(vec![ContractEntry { + protocol: PYTH.to_string(), + contract: "oracle".to_string(), + }])? + .contracts[0] + .1 + .clone(); + + let price_data: PythApiResponse = + reqwest::blocking::get(format!("{}{}", ORACLE_PRICE_API, PRICE_SOURCE_KEY))?.json()?; + + let update_data: Vec = price_data + .binary + .data + .iter() + .map(|d| Binary::new(hex::decode(d).unwrap())) + .collect(); + + // We send an update to the oracle contract + let update_fee: Coin = clone_testing.query( + &pyth_sdk_cw::QueryMsg::GetUpdateFee { + vaas: update_data.clone(), + }, + &pyth_address, + )?; + clone_testing.add_balance(&clone_testing.sender, vec![update_fee.clone()])?; + clone_testing.execute( + &pyth_sdk_cw::ExecuteMsg::UpdatePriceFeeds { + data: update_data.clone(), + }, + &[update_fee], + &pyth_address, + )?; + + let tester = PythOracleTester { + current_oracle_price_data: price_data, + }; + OracleTester::new_live(abstr_deployment, tester) +} + +fn test_price_query(chain: ChainInfo) -> anyhow::Result<()> { + let oracle_tester = setup_clone_testing(chain)?; + let current_price = oracle_tester.test_price()?; + + let raw_price = oracle_tester.oracle.current_oracle_price_data.parsed[0] + .price + .price + .clone(); + // We assume this price has 8 decimals + let price = Uint128::from_str(&raw_price)? / Uint128::from(100_000_000u128); + assert_eq!(current_price.price.to_uint_floor(), price); + + Ok(()) +} + +#[test] +fn test_xion() { + test_price_query(XION_TESTNET_1).unwrap(); +} +#[test] +fn test_osmo_test() { + test_price_query(OSMO_5).unwrap(); +} +#[test] +fn test_pion() { + test_price_query(PION_1).unwrap(); +} +#[test] +fn test_osmosis() { + test_price_query(OSMOSIS_1).unwrap(); +} +#[test] +fn test_neutron() { + test_price_query(NEUTRON_1).unwrap(); +} diff --git a/interchain/modules-clone-testing/tests/oracle/pyth/mod.rs b/interchain/modules-clone-testing/tests/oracle/pyth/mod.rs new file mode 100644 index 0000000000..f8c5569278 --- /dev/null +++ b/interchain/modules-clone-testing/tests/oracle/pyth/mod.rs @@ -0,0 +1,32 @@ +/// Integration is used to test the adapter implementation +pub mod integration; +/// Live is used to test the adapter deployment and make sure it's working as expected on the live chain +pub mod live; + +// Use https://hermes.pyth.network/docs/#/rest/latest_price_updates to query latest update +pub const ORACLE_PRICE_API: &str = "https://hermes.pyth.network/v2/updates/price/latest?ids%5B%5D="; +pub const PRICE_SOURCE_KEY: &str = + "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"; + +pub mod pyth_api { + use serde::{Deserialize, Serialize}; + + #[derive(Serialize, Deserialize)] + pub struct PythApiResponse { + pub binary: PythApiResponseBinary, + pub parsed: Vec, + } + + #[derive(Serialize, Deserialize)] + pub struct PythApiResponseBinary { + pub data: Vec, + } + #[derive(Serialize, Deserialize)] + pub struct PythApiResponseparsed { + pub price: PythApiResponsePrice, + } + #[derive(Serialize, Deserialize)] + pub struct PythApiResponsePrice { + pub price: String, + } +} diff --git a/interchain/scripts/state.json b/interchain/scripts/state.json index 92facc90f9..f6e6e7297a 100644 --- a/interchain/scripts/state.json +++ b/interchain/scripts/state.json @@ -7,6 +7,7 @@ "abstract:ibc-client": 11530, "abstract:ibc-host": 11531, "abstract:module-factory": 11526, + "abstract:oracle": 11560, "abstract:registry": 11527, "cw:blob": 11289 }, @@ -18,6 +19,7 @@ "abstract:ibc-client": "osmo1vnt8tpxrnukcydma2x6gy2zzawl9uxmc6las8cak9sd87q67n00qn0wkj7", "abstract:ibc-host": "osmo1zzgxwn88a3ec34fw4mu8ppsh9eth746l3tl8w5l7qvknrmtldldqz7saee", "abstract:module-factory": "osmo1vnj802lyyupfaez73w7axfs3xveraxen370vhcnumaufj29r5rxqcxdtus", + "abstract:oracle": "osmo15sgdmhuqs8zcfephzw60kteh6wzd6rngfwwv6a4g6g8f80zcqqgqvcvruu", "abstract:registry": "osmo1cag6cwygef6fuddgq2l44py7crpscufrza4mt3rum2axueemenmqtpxd7m" } }, @@ -28,6 +30,7 @@ "abstract:ibc-client": 8233, "abstract:ibc-host": 8234, "abstract:module-factory": 8229, + "abstract:oracle": 8328, "abstract:registry": 8230, "cw:blob": 7399 }, @@ -38,6 +41,7 @@ "abstract:ibc-client": "neutron1n9la68zja4l76plwffedj24ar3f6e5kg7j92r26hhzewncghypvs9vk28k", "abstract:ibc-host": "neutron1c67x66rln9mgrjum5urrgn0tjvup5k9uke8hgdm8tu7hztwrjy4s5ecrmu", "abstract:module-factory": "neutron1vnj802lyyupfaez73w7axfs3xveraxen370vhcnumaufj29r5rxqv5yh44", + "abstract:oracle": "neutron1e43jgpsqeae5euc2jrzp79vn6gv3w2gwtlnw372w6tlmhwlw04jqmgklqn", "abstract:registry": "neutron1cag6cwygef6fuddgq2l44py7crpscufrza4mt3rum2axueemenmqln03h7" } }, @@ -68,6 +72,7 @@ "abstract:ibc-client": 1374, "abstract:ibc-host": 1375, "abstract:module-factory": 1370, + "abstract:oracle": 1395, "abstract:registry": 1371, "cw:blob": 1278 }, @@ -78,6 +83,7 @@ "abstract:ibc-client": "xion1e74x0upzwsjvt6p8t5wu33cdnavsn5kcl6ndf8l2hpeah9c94tfqs6lx3w", "abstract:ibc-host": "xion14rwy72dckjtpvtw26yppgfr6jqw4y06tf68axefzk5xjplm9ue6qvtqxjl", "abstract:module-factory": "xion1vnj802lyyupfaez73w7axfs3xveraxen370vhcnumaufj29r5rxqhwxljd", + "abstract:oracle": "xion19g9zd2vjpwr8ycfp5zpd9txtfzdryp20fa75zwrpp336uaqdazxshcud90", "abstract:registry": "xion1cag6cwygef6fuddgq2l44py7crpscufrza4mt3rum2axueemenmqyfdesx" } } diff --git a/modules/artifacts/abstract_cw_staking-archway.wasm b/modules/artifacts/abstract_cw_staking-archway.wasm index 84865da9134f7ffb2ec7fdef7f5239136d6c4b63..24d7533faa24fb6cf94be46462d3ef37dbd94955 100644 GIT binary patch delta 5772 zcmY*d34DxK*LUtS&oYx`CNfE8vQ8$6BxE79A&q5Xt7uc=sY~ zhm_QlPz6m+!D;AOs@KSA&uoPCun5+`Vps~FK{_im3lwL;am<&U?~(1*h;p53B833StV>^2HVQkz|g#H>`<-VVRnR_WT#ja+s00_ z6RgTKH19IILQ}p$+->YSaerXHu$$~Bc8&eWeq}$`YW~)j-66&-X__=snkUVW?wGbf zkyI?rm4vBJq*Cb=L#Z}AX|c3gS|uG~Yo+DV&}}U5N0#@Yv`$(ht*?b_kSe8(PzfuD z-Y%`w7pgr}9hREPO&j%UHQl^}fiy9$fybujI)2pWws_u{W*z}XPS7QQVBHm*19ocD z^pfB`M0c}Cg57w_eo;U(pXeHA1h6tbs7&den9>o^?M4lhZ%gPcP{hWekZw zKxT}_joQdy)hn8$>x-I%LI{nz#fAIZ{9GoFE#IZMn8%cFi}1JplM!jSQhG87F-E7& zVWhvlWwPG1*=!np(yTMJE3%vGtuhK}v^V1l9McQhc=WMP-}1_n^#z$u;VE-REnVDF z(Cb?YdPTOdWYP6j6Cm1Xm__E}h*<|s&(QRlt%HcSH=~pBed|c!{ZZRG@qgPz6J3#+ ztT*!f238|9M+U?F{1g@)?UIsMl4nvuLBZ(G0gPs5@|@TAH}EJf%@%DO>~@(M`y!qO zBe%n21}-DF^H%^aJe>o5jlwSF%;@as58&3OULppWveG9ubP1^U~sY}Tt^{=f+D?ueurH-E1!BpJisa{v)V z!(6m7n}!ugM8r-A*7uDG*2_j(^#LP;{=sn(wP)nvCwSLKS@oTx{3*S4de=uq5T(8^ zP*vWxPV(1itA2d+li0sTyP%;S{ei$<_O?E33OIy4`tay>pvbYO_8e?+F0~47U zzc7z>f^l|HCeQuwM0=NOVEuC0T&id923ioAc0h>HVcESv z3Sro0x884)^Y2lBesQze7I|>`q@pTUePn&Hl2hb0mC+@>yC=LQTK`UmSorpNh8QL2&?Q9~9#bhuTq6rXHHeXm`j*ivb$z3y$rvHWoX# zg)bGI0+=4OI>H!xygNXse&$4HZ=0rfI$7o&B^!RHZc{pqM^)tw*@`7b`S*)K^jSaN zu(BORMsoF5ja@G?F8w*CAy_dl5aKb$4slo>2$gs}9{hQ4D|93ixWWc)AQ8W_!5$yg z1pR`*>?e7$^IhO^%Il#3DuGvUv?PL6QcOwYXq-NY-3- zdKRp_+77SQx@v;^LWTZc^GM$!RP#jBr%s=wLZ5>2BCX68^*0fKox^}O1ojB?hLh`n z^gz#IabuV$((HU&2omoph(d?}H?DI)2?en^65PCx6B0xSBzNPga0mx4){WnXLkz?U zh0SESG6J$8T69e@DiZt&o5qxZjPb_d#Q?EfM13n0m|-7tP0t zdt6@Dd$DjIqWMra90rQ6X*}#E;ji(u^dUSW0ZhTf&1?yDJMp}ha9RdCE^iI#*s~2B zX4@9?n6~hoxX*Jtr{N+GIK9ITIJOfk#^M|ZBWr7OAQ7ybuH{DJb|WN@?*uAko2PV! zfzfPtIiEKO9!9gf<$UfGcw1%D7V}55V1SkFTaE+D;5<07^%96riu9Mnqt@;%aWO-_ zOY*&R?4L|qIL=%`^^6rOrpQgO+frJ*5Z`#gQkcxnEaT2)@JTZ4#F#X#6@GLS+G6fe za1 n%0sNBO(LNN^uJGUDnZ|5E4O|V9n75(LY5N^Z6Iphk)yEYA zur1^VlG$^Tzke+hY*dq3Gg$|@6#O14SUH%*xN@S@p0E04F zFm6m`x#&q{?XXW8i#P2z0mC!tED{TzWqy2r3l_%kVJdqiDvI2B!%1z>z{5s(emb$g zK|TfHk!;sY!es<@?#*KOy=H6~L%&q=J0g>1;iOa+=By8IzvNd>ECiq8twd66l*AGM zhbOXz!81VM##j#A(bW(c%;B=J_*OYYBpV z#PK3Fn5rS(teE98aNy(;c9_U6^Vm^|Ehy!|3#l??2bXZZi2dP&8op&K`!kCDzKm}^ z!}{O>+Gxs3B2tc)=H`? zF0_1?e_b^bZ%e>A_gLXSWVM9{$#~*@c8;-&xZ_W@B$VA;&X)yAx9HSiv0b9W%q#5D zZZX@pLZ!EX-74ef!=xkL3)Lx6amDvLr5V6(FXGQdNOY%1^SO~ySMeV3OHtC@9JYG} z|LS!q-3?(V7fLm3;ZpvvP^$Kt`hBX@O%^siv!pHx`J7ea_4!eWv{QsIaK6-y@=jfI z{CU3g8L@UQkdkN(zF#1HOi|$yl(sTn#&Z`*DMDj>sW5;`MHh;M3g_oarC?x{$bT)9 zK2g}wrF`Q`Xe= zCxzdty*xzFAGVj_~YhMcQJNe2h&x!yk{5-xra-|AG7|b>3TK@EDnDFPuI`uz1(8@+pCEPN+v{69s}N zPn1){-PWT(z9y#cnOqNPS}0R##-A^g|0R}(40oc{tIEd97|oC=pJH6AN8iMo4H-SK(aME8~6>CgnKkoz&@*@>4{~r{pcPJp7bgNuAfz|5ee{>c@crQ_fTEU?%gCR7~<8 zs^odV%1`rAXXIB@j8K)1P{7|%l{qGU?3^4+Hvm7wVh|3sPB#R&DZ|WTlT`{O)%pVP1S7+MJ4+@9wAMcBEDFU#0A$?nZ^u z1n;d<#B~t1TCn)J)yfueux75SM~ql65Pbf6B~cu#JsXq-0wT2e_)W@CaYDSN8dfM` zYo=Dz=~5Mg%`3fzt1Fc(0ZiMfbfBX&e5=x4R3-ep63yU8e)fX0Q)7>3^SM7M!Tz}S zmJ%LV_~dhTmY=w#BrE*NBV{1KHRD-FKVV-n`nZh7;rD61zvR2_D`^UP*2$yrPKug{ z|6M1~#Z9SdIG+buB2Sm9LZZpJF7m*t69Q}~u}^#qkjI6k@_);C7L z__!EVd?@k-E|u~VC)Aqbm^ii2XD)|s6*3Vk^3pevtQR#>>C*$(H1b*^Rt{0i69vV4 zCaDhv5SyrJIJt>xClQTHp_FH&s47LEKdLI@U!|+_&A6qVI`N71ePF_LkJ_1i7lNZb z>R9}`m70m0TB%JiD@)A`xfL=cQ*zNqbp!e^*px$G?ga&*d|H;;0dQz5wF6qS2wLq? z55RQXo}&(e={%yn8VvY+w)!;fvchaN*2D?`U&vOSc=;LiO`g_4U1{+>|H@0MKX7{f zR|0SNvf8mBn>U-kHc+h!V2g`*@_*E33OvBxqt&7CfFByI-ehd=Y`%T0+Jc@Cer=K( z0n{snYNp6xo2hChe9lKrRT~L%>2x)Qy1m|xUz)D=lGx`AW9O)0Ja?A*JiwQ@v`9@P zl|x19t0vgZBTCeJcK8E>*Qg`l4?bg!3K@*g;j_M0yE#RUmJC#qxO7|H&hXG3^R%Akyh(S ztpzR%*Rt7}2>iEAb78j!sy}KG+AhC9ss=qpR}VDsgzyECT30JhNY$46s^v1+$*D%p zvg6iJWj==Vr)qL;igpuDVaaRkS^V|@wB_U5Yd^=UyCj#E#B3OwAUUyci1s?{;y(@1 z?kd3fg@0=g-N2E04|nR?M>6cfLyNRG2$Q&2y9L0fJIXZfC^P%#VL`Q-zIGb*@k6zNjjm%9P1N2x?_$Ix*gH~WsB8kv{jASzVNO&MPQxgK`##){@%ae9X<#P z+?FWZdXMxs)tJrbch4M-U*DrByky!vb3@V!!J+qwPZ9fJ%3Xp*+&8xpf!VS9J##-^ zc;8%VcLcd@4eay_qhC1vqUh(MA4UaO9N6Y}b25$!u-r$p+Y*bDtd=xPvs!|%X}HB= z9q@ie)2ys_hQFDW)t-j9DbP~N2@@CPg9oKqT-r+`2mR-R7lyxyEz>N?cq+vb;0ym^ ys-=%N$}y>yP>f5p%upBl)37mj+uol)pF>HrC=@a-AIGlq*_yO|a z09=OxI0!dj3tWVs;WDh(UsLRkm9PRngB+CAKTxWS}Agdz5TxpgxM_MF(BvqNV zK&~`jS|ABmUrGhi5r$G-cv8N!URo>dWh61Fh25Gaj8aBfU z;)Jk-vWIc`pX9)n@7!%(sj&eI^3L=oOjehO_4Y zFyfwB$&7N#4*+5Mt$<|xY(OZ46LpRFvw=|%Zqx*xmyC7kg8&@3`2If`|2YI@gR(R!NMX$%h? z1IDCY?IAKI0Q{Yb*OcuvdCOMr_Vb#Yk~PMk(277C*Z@bde!+>F~o07 z^yqP^x4>nDww3`5J*4+^40uZk)BC+pWSmO-i$Nl0dm$MwdMOJLT^0ffj-|su!`!We z8ICqH7)0pH+C|auJKJ4maDZH_&__H!3>;z`=qvvDzFzslCL`iSdlU`W`rWP&Y>a-_ zE@qcI%1No&IBJ?ijBAQb|LOyqUN|;bA3QeXZxSbQyT3cYRzW zaq4)1D)+VZnuimD^+OY$#6FzhgvNTz`vQB}*Vba2L#*&;{Ph9tJ-0Dv(r6Lp$;pH> z3a0!i(E#(NJE`5|YmfQbis|vt*a*wv3YnD88A_J=ph;7Vt#fBcthm7FF#l-=>x}6O z@0rNWAsf1*UY78At!z&n zCVr>j1^SJhF<=*HW97~^!u{!gi`|#^wP<^MBhJ9QZv@?aZ#PQG%)L_??G5?Be1N9< zl7qW~n~JmErZy2h1DPJOI?|YU=tY1?{rKTtzBXC!d8E)sc?|!fe^N4yN984r*k&|J ze#!^Yr~UGKF#C3%;i=rJu~~V>5BEQ41TM@9f;h0FGZfrd5=57poo5C^CV9XWR_FrF z@S+uV)pAMb9|C57$=fO030`})wHcldX;22+AkgMr_8Bcvpc4{VlxUn*pQ9ust&O}j zvB3lKM&o@8E?yZ5FVzi|gkOaT`-h9j-Xcu1L^Gh?p0vWAg7P7Qnbq@{3B+FEK)V57 z4u@UXKL(m$TRTM1lrrtm7CZ=%M6a{MLK=Eg6u9{S2gHkkN$h=>AaY0>PE5)Lh^0V+K9P#u-c#SF*n9H{?ZsQ>H~i}wqYEief~s@`(hg~MNXQK3wJqv zqIX?z2O{`LH|zt7uw@+VB;}1bpbMR+#)HX5()JyIZX}-70glNKj>|hk3ij&)``E!E z9@`b3p_40aL)y8IFGacURyikzslxm+9_IIJR3C<~^ zn#6^rGvp-fUF=(CAHAd)rn3#j+_4P4^uP}Mu({R|KRp0lG4lYpNf6ya>%d76nF?od z|2-H3XL+alFfRhm;GxEB5S-!7!q{bvg15%9e1HTjbTJQ}bh2=W#_LX2S}W>C+<6yq zp_uCy9q-hHZ3Vc(Z^bc<;akaU626jbZe*)CyxT83k@-3OyqD@o?BAArCMU4Q&;g%M zVGjJIEsG5cBMbrEq7jsd-u6FC9NMv_fIp_OSFx}evxMxH{DW(e0teP2-Zz0gBVk%w z78epyt7$ODXH%H>N!KQ!(|oS+*JL&nC)%}eG^eso!hIm-rm#4k*`7TIY`qC9nz0z% zmCB-dMF(~hcu^`_#`xwGmd@&9pPb5K>*-&HuvlM|(M8}NP0{&g)WXlt%f@&g)J@+j zi3D`<52%Y3tfl-$Gd4})9iL*`qVU~JbvaM&&lq5+oh|0mvseJ|manpB6T!wO<*--j z62$Lkuy}~%k7lq$AaTM+%qh_!Al}Wh=djKaKAgdt@I$$57}X%W)qIx8AQq=DWc!GH zdJ#JyvBSmO_AwQq?Du7yFJ*Tfu#Rup%I-(AihRE5I2#zmzAof}7g&}GiG0`<<_2hl zbADxKi5>DAlZfRbuChnKY6|&?>+F;UF}!OP>nMfQm0Mc2Gr)UBr`t_&##v)9uZHFP zO;=Znk&Y+aVW%1UB7ggRRusmztl-N+qzZBD=7&mjnt5rcv{TIW%`oXLV7dAHOt`dP z+-EBs5*0Ljw?mo@>{tPRCQ|A_2c0j7lAaaM0RJIcx}DChmGJ+(E~U633gsNBnk_8k z4|1eRpQ}G+O1)*_(>qssS|Oiv7y8EhbfHuxLKw1G>P=avt~Fj+ES(@x*%B#{R^X>4 z(&rQv7NNA2okX6wRBA3PCKm_?SS-3oBvb@HT_D+Lw59w;q4cG~%9iraR!Zx_*q##p z@($^c0?TH(c1zr~+jO)WEzY(Ixt+=uui%NAyvil6jdG8i?V#{GX2>H1|4D|N(TJxH zl+OZ4dVlLxoH{`M8otwAJ#S#rtMW*G@x8Is-glc;6pU!c?Q$?R*TXZxaX4Gx(R-HQLZ3W=}$5pyJ@`oXSogF!PCSo;KAR^ zc_x0#Ul}Xm^k5|};=ixOBUfu52(QFf1}l3)VG$n^r#Jx?;mmkt4za;am1@?-CX%&T zYAB7(PUbDYLV<^P!TJ#Xu4Yc5{!^$GFS9=6=^mvyut(+m-DXO;40*h3ONBl}@-VBF zGK|=-S}Coa6ntf0r8R?vnDC;q78dejFDf3O{_aak2L|&oHA~q--K8vLJj~|V7X(lCWl# zB5sZF)k4HiuU58*<2Pqr17gg2f#8eRD+%KG?b@I$5fEX`CvQ|nigV<1)u>bv8@NSj zy)9Kc*m|?iaph(uO#qX(D&6V8jozwch$@DkQDPVr@KfiMGL3D@;|ne+wt&Qjmnuhk zVp^yE>m|8}Bt#In1}5ID)B?GdIwuTg$N?>c!LRy9`> z@W*xX0^Ha_jo^zw?G#QS9kZ+ANIq(!da%@?(#4MD4xh*yr#9zXBGkj8(3%|602>%9 zV0==nDn2dw5~oU8vk9}-_(2mjr`BCM-ALrZC9*XzfxPE7Rq1mD*EIEcB2hYV%M%30 z`z5Lm1Q3(dWSpL)iZ2DC3*Zhmf&QqxkpCw|U2Mh;oz(7lD@{$pvNW|l-t0tF z#8Ybf#uppUXfHYGR|-G+aM+kmzgtYJXv~K_rFIAWEJK|R<8V`k>cF?Vs!_D}=5|$G zCR;VOZT!?a3B|Vdpe;B04&&dtf%6>#Poi+1%SjwE<7= zuCBCjDk4_a)el4Zs8l~RdO_{ch@H#juMAPk1KGBD-1DB=N`brh>I8Kp+~s>Gs5cqQ z&*j@Ds%;ebmS6i&jRfkI9JRejXP233d-#rzo2fPxZ1F5Lmbx!|9sgmL+FxSdF?8jr z;XHG$`kdGR#kpz%ne5F~UoydQ9=TAh359!TTceJFdwlj96;jzp^Z4BF)!q&(?KKVmY{kNHkzMNq{qRB>Ym6Q3S~~VfW!9(} zH}?3dRZJ4v*A2vE7mQj#YDF?|W(ho`}?T;QRz z?p>*CtGTwQ6*vR3y z>^2GdRGH2AV_!>W?AF2(E|Bqfxyl@cuT+`?FtySghu3ctWN4*16%SOJ)6tx42@-xR zXu3^q3F5>>x6Pro6t6UgV9#oE5T24{X4z$>@%O7SBjtjKh!9Rj5U9n|^ z#e#>cX@>WLEVCSg$EUVTOZ(U8;c00ZME004bnw_QL!Tc#T!h|-mj+v^qiQqdOtv%% z%oyK3wN>A-L*IK}K)lHor}mg50~hXZVM#|z6{TZ?h|-ssKFOq5bDL!Kvl;N%r3?F7 NE!q5RvL!h8{{iM+Z6p8y diff --git a/modules/artifacts/abstract_cw_staking-osmosis.wasm b/modules/artifacts/abstract_cw_staking-osmosis.wasm index f1c3841c5da67c534d0752689ed7a8d7e8424fbe..60cbf1bfb352766dba4b523153201b46d8e04ff7 100644 GIT binary patch delta 14932 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 HgS`I-P{0RL delta 15100 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 diff --git a/modules/artifacts/abstract_cw_staking.wasm b/modules/artifacts/abstract_cw_staking.wasm index e1b69c72221e7f4adc5b1c2a7737ccb1e7cb973e..6aeb5af3ef75b6e06c9de2617153cbecf187ce94 100644 GIT binary patch delta 4676 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 EKi!@ITL1t6 delta 4730 zcmY*c2Ygk<(r4zJv-c#qNp31!(r$V}2?)~bjRd3zgutUF2t0}p0TDhdBuMj#v>d_` zS_r7L^aC#Slkxbr76~7Mqi}~f@)?cR`kz? z31^`g8aDnGjzFWsa1;i7VXW5@(z75F*1`(d2+QGn_!8E@GWZ-y;3TesC1Apjun2yF zrEmbQ!%8>^zra=~g9~s8IP8aVxCsA&Qlc)yA!vF9(tn1pU<2ep`c>Ejt6@D{0|Rnl zGpvIxunX=(69Eq(;a9i;mGB7CACm8}11n(xns6MB!Ke6dT!f2pDOSQVT!NpgV+U@= zEtrR2lC%V1Q#8=`~qmrdqR>MW*vXW`^ zw=^+J>@}eJTKzl>2o5pN1RVhIGna>S)WF}cM>a7qG7tiY>Ju4gwRt#Hr)`3RInb$2 zu+_DC|6Nee{48=1LV$TKIvLcR0NRQk;4m-g{lIJ<+X2Yrl(?^HoSYDE^otLbR6Ox! zY=dAlXIokW{A`pZ-!wYfr$jz2AkX?pt_C4|Xf!17lm-xJ9`RcSB-kGV!_BV)a?q@o zI2R$zSlcC-!r0yAS2TZU*AmQvP9p)r4KL^0G){GXW&CIzQ`g_2#G$`)c1A|V|8(;N zhw4BF*g}lHo|$meSl{gv!)l!e;e1^q&1rtp>k@qyBehQ=MA4XFobI!i_{DvLAQHQP9@yEzjIg#L#^z5QW>!Z# zm}lP%2WY_8HqsK!);&H1h%>hLJem2{OrwAQ0(0hD9ttIAUP>p3H@{7(C%?$$K@JEo zYX)V=m5iZXU1JNQdZ-UkUc(N%_!y(ZaBstXxRtV=F;sFvMEzs9Ty>0iiRnAi+Xx={ z64Q6210s#dBjswV)R&mysUAj?G%w@u&{$)5s&2lM)&(HIEFSfq3?_Os;mkXu?<-{f z$~XtuGsn|lguBMX@zD@zjvFr+X*ed2Aw{Ej)GSk-I#(%NZum2{9kr>QY+j=TfubDj`Cb8ax%S}}LIH+f0TiZFUFmnW;1@-&WR zxv7o`HoMU@H^TUK`6|~^JJ;BR7Ufn`vzmDRF^@ipn**GkClZz<#v3bqX!EIA@#d@* zEiL3o8Yo?xLqbVquUkbSNGc^KhgPM(dh6{kWCPZ}lm+J2$_~81ByaHaT<{q=)5)3t z1Y3YhGkHTOIHWam*@oApv%_2DZTNVr90x9pH->MMcjBXMl5d{ZnX)o1FCFO&JS&qK(rgT^&<1elM~A#jS^E^RyWx^ZEOZTwgr9)?9it8|2*Z`#auv z;+|>0P@>}}_stX6KJ+Fx-S0c+#?t#mR5hFrk}3b0Pa7Kh9{NFqar)ujTDJP3 zn}_0TKY=z>Z-OntI8j-o~O}w1hhU?w{`J%izt6M;*F{9c9|EwH{Fnd3X zmgmD+9bsfWuTLLBQfHor(I#dP_q zY4gdHT7thIy=dKC4|YHtI&3aS65vIa+|;Prh+HaOWYJxJUE*5X9Dix^k5Ibg|3>P6 zwdy04zw8q!ElGe-{sJsgAq@O^zA7a=O@k^36GIpr1_POPJ zV4!j!x(CB44Wjt6aA?Bcj3AA9!aEXr(gBbavs>-tDx8HpBL?b{U}X%%g1?~p8AGK+ z!dh$!ZUB^35z-KD_~N`=!8*b{Pw^}nI=ew1(Qycz^Mfx%z$6eT9`~dU4$0z7Z|H?s zxQ08D;gUE$8RmQ8x*R?r9nOOk4nWXo7) zLsQ;mHqgD7G&SUP!u=EQ@KZkBzMoILWof|eR`eGAvfxkvJmKSRvNpWWHb{dfqG%he zNufRTM$85X=4C3zbDN5FA(qFfSXe9SOq^XKE{K2Un#4?oVc_ds$5AH^<&VzfV(>W3 zczF+u;#Z^4n@`@z>WTT@_!M~~Z*<4Sz+?Sz7;aG|C{*;cq6dmycI*W_J_y@FCtl%; zc3xt^7{1#J+wd}9Oy-Mq(#=rB5ois>d1)kT>mx{=&O1 z&PQpcKKJy-FrIbG;>!(RY!MJxs}DUjeOgIiigvc3(trhUAW&WIq zW9i8v(k9_R1aB@T<6&ZFO~KO&UR)*my-!aze4Z_;X5g+6C=?}GxX_A4Ty)xiyLAW= ze{RJH*+N6|@B*<_c}UOL2BJD2p94N$EvgIA#~tE?*KTa11iBit#i>tl_&CqY0>d0p zwm3d~AI^a|UcL|g3HoRsz47q3mEzQXoNj^M1`J3L(~jZ*Z@4PHE5&>ATJ5<&=fz+A zd;#~!E%J-_4&aitLc5Gd=nnA{SCERhxN`+R1>C<@OfSbIy2oPgHS8%1v2gnZ!x;4D z#X4oQ<855s9t?3IM(ON;z9Oib!VzM)*t&omOkd}TfE z%M}~vD_d0PEqX6hFrP|8a%=T`Ln<5%Myo?D#Lu6o?j9;XYvK{Lr3D}5h!0Mx^TMI; ziV8K9N{Db&s55NPcgIR?7ZSd|qP1p}g@ta~IJsQurY-l6_^;!x%G*l4)mE%}yt+tP zVq2(YB+;Hajn=-Q$uXI(K!Y)w+-8q4QY75RYQ=K%d&j*(Y#J{S;>dU{R#w5g6SOP| zk=ml@U)p$?OP8sncQtA`JoVj|x>S<+*vT%#F;ld*5|}ns>jDAdtEt)>vdrGj)^2En9&-JbOC@vPUR8v_BAwE5rk# zm0RGpS=ea=U>4FlH+jsv=$XXl-*s6c5&fUw85NQft?p^n z5;)_bmcU0n)ck3Q=vBD1Likl`j6yJe-?3WksM40Z@y|5Yg`ZMbL%vdBt@ufes6UDF zudvN+r8wwOUx!{P`HA$*&&Uu-DoX;)0A7BM+4&|b`zK|C=n&ptXZ2vIn5eUG)$i3e z*{OQWLP&>Me3_N`@lnXe@}H1(#q~ZsL}4HDCmK5dNBJJc#=ub#Zee~Pygb%v9@WO1LaESA_dUD-etZi*#6*kga#%NLAf(_pWt9?75?uDd5{ zma&6Du%1uZ#sau4M)Tu&k($mcBQ$RT1uO@xuQqF{Jg11gP1{k5*)8#;nC*mGCW4D?I5>pr}jAZD6=S3CMO+Zvvk=;-s0|O* zM;7YiMP1dIaqK`HXMk<9>hX=jcb8K3Pxw?AyZH2T zERkP5$J)SEUcZ#R&Uc<;aU!FPb@S#WiPQ=Hc*g$VM{cn7wGV;SG|?NNwP=5fQ8hoo zi|evC`TmX2PNdeb+fneC_l&Zn!((wQ%JPUo75}D>#VM3VmOT+rC5XAB5hibdC5xA2pBdNS{suQ%eM z`MRBZ6zYw6^L#ys=jH2JJTXrX{L zqL7HH%jXp84nCql_vU8`^#y!up>B7dHgocr_u95inlxR8U6-d8lDlC=dT&uyq>qi^ z<;Th5mQou2RZ12o$^CUH(-S2{eY=dpypTs;Xw{crE+gBdQJ0@Br4+byH%rKKa7*E9 ObM*i*_`Dvu@c#ins|ZH` diff --git a/modules/artifacts/abstract_dex_adapter-archway.wasm b/modules/artifacts/abstract_dex_adapter-archway.wasm index a6931ca776d1693a0c9446c74ea134933c70895e..daedafde624d2409825e935506f8a8ab93fc8b38 100644 GIT binary patch delta 11431 zcmZ{Kd0>r4*SItDY&SQ{jV!XeVoPF4Y_Y`>Tae{OEmga=XcKEis|_M(i$p9BP7q7c zQacx8iJ-MrQ7NjFqDAdeR4L^dpQ=k2*_aC0+n&-4oB6W)+iP9uC7Uz8wS{fj?j;+=8#5 z82*NB@FP5deQ+1^MvBwTfL}rSL`eEBl>YW!Km$cAfoJ*82y$!9G>fdwt43=TrF%ewDB}{5qS&r|~>K zg-_>`c`pBqFX2ne#+%8r=JIU*f=N{;@|SEf7kmrf#*6q?zE<4_JNRy1Na|c?M@Zba zWo!rdLH-jz%`dQ@`AJR|^qS0jo#N;CS$@8ZZ z?5fQNz3-{<&Z?dn05i=^4ZE7jjrXA6U+R6+BdC+JThl(^JZ|d?=91{YAi(S!9q&97 z^8sMUUG$oOfF^X1ubyf_MK_>p6S2-UQ$@H#eJv_x!=%6m<&Vhy=|UO+Hn_ zS!=s$UI_>_Z^YZpjSUBZuj$ulBfG4d>%v=`oqS)I--Se(>q6bkOutVF3H}N6JZf)X zj`NrBp(-8Bj+MTEVsmYHyqO>Lz(o^jZVe8k!A=D4D1$eJNcd=ogpb-IN#b+}bT$r~ z!@!R^%E{JM2?Rgqp(=wJ(bcI|-tARA41Aq+tA_wJi8W|`T^EtwMjwE1{Jf$OW`5hC zJ%pQ|m)=dO+Q?o~E)PI?Fz4^OP*-VU^MRG61NgFQ2)izUGRB{#=Qy2uARjeVT zP)qAIW^Qluv1zo~;EZnD*6vxDy{|%Kg$j);RIqFD+nf{M>8ud*_d{AinA7@R04Zcv zd*2TJ&i3!0B#hI4ctuW4jE3 zq4_Ro)i_Bpa(p>m{|UimH2o)dnVTkfLy-B+1c}Ybl27-%Xy@dK76w(FGbUZ3d~=SN z(o!YFhH33d-3`;C&8pKYSFPr5v)V23wluq8x5X=Iw(9O)|J_l;IcWNujC`;scfV}1 zW{#0o|22z7aTd*f#KZmUN(4K=%57HcI@!E<8rf{Mv-prSo1b}lo}IM)%k}i1Umb#+ zar1>n(jFBI0#YYy<^<=@OQvvkV2QKe@=lE1E^vOm@+%KwO5M`j^^7)mZ*iwL$L?_R z)|LWSU%0tstA|I~P!Jy>hf3Yz>LqH6((pe!>TZ?n<><7n(qpAi7(__1&P!X@N)O2q z*6;d)(2m_jq@09f3cnzXB!5&Wlik&~=T+aHSA9k0eKC7IJf=)1Cm7@n-!z-Qi#uj- z7}Rt+_C{(X?&E_yynO9Ef;BAlT?Y?~8Gks~?0sk^VZGKwn!bl=ZkP=Y%eivraBJ{& z);ThnQFd-VIvc=lwmnwlW&bY;OiFOpI^F}Il6mw*U31fkK-b%Mu4klk&kqkMe%Pgt zvB;VD<7_WTGA~}K3yDtm-`X-ZeW|m{)ffPWIqBMap3|3-{#ETt{47Ybb#XqqHbScX z-koYt)0}aqm@MgkHv`n!f4CHG03i!8=``ox8hhIB%Jl~DFkl&nD%L} zK$!^b%2UY$vn#R?9Liu0h5IFgcHl4Caj5MLfjG(+Xjv0;eBlQbLNGK4qH%T*ZS&I$ z#9P78kydCN77lgsWGDodzF$Pj#Y*&ki82^`g z!7T=fqGYAzh-`~uj3hv>4sb;&VxS;g*Q?>d3A(>{KZQf1KhF|@+9wP1`G(;2>&MrRLz7<8mSOR_aD z1$t7S_@fI%F!F@08+0MDZ+C+@(tc?-Xh_ZJZV*exx=CYCvb6YYX{=^*;R7+YJJcf1 zx4T1UqFvt|@~P?216q*yDLufGk-Y1@Aq+S7gl;sH_7)_|p}O^k2Bgi@-q5#{BAXob zULSA+p5*R=QcO=k`nT+E{!P^909tE_cCy9SQfGF7=kpb_M+H*39*n#&l zU#qZduf%`!P0UKk6R*4`mSWcB=$3kshQBm8y!o?d0TPD5@;!o=E6J~paHX> z9)n>xXAYzh`0pIpA&uNV7n+h2OXiXjhhfS*SfwY~H4k5RKU_Zt0?>Cp1t%F>&xd!& zu9fql2?dfiRUW^Ovi9U=GRdGo-k%Tc*_DMN7O93O!h!`5EGjOb(%tjQLZYc!%0OPO zxCmNs{C)}KkR5L>g@=+YX&Fojf}2>p3l>r{aGj+Iy6vXCJGah~DjF0*rp&uh2Pp3@ z?S9!qRBnO~y7yB@<>IrTk0ALq};UJJ9WW=*S)JDmsoqpcwu=T%f$c#1qhw;yU*P zELOrC?pCYa8c(GV)j~>Zk~o)gJAVV2>tRb0j#H2(HQaU9rJ?<2mxhCXb`7@lXP8Oy zW}PP&C!BK$oplb5bIM$I>~f0MnT(5&r^9vR*I*BojQg*_YUzWtn-snz?0XBEq1P?2 zlE%TeXs#t;&s#42SKOlM?Z7>Ep%Sv&kVNV_Zo_uUQK8+1(Ujo$$wQgKc<~`krxdLJ z2vUh*@*_y`D_f8v(&Cj5;*ZJTDzqeBe+2b8T*bgAu!Nc&Pauzmee#s1th28OcSvUkNQWGQ z(PD?c8H_?8YFJoj4MK607pn#lINytXUs_MR+5{Nxx3LhBYh%{|B5`y@I%q{=|JU`S7t~^A_^CE>}HuxWoq1L$j*~XzHP*0@>*iqD2l%)?r+F^#q3ztN+p`&=IjHa zX&1+GAxRX+u}+-8;MQy^&DWK!>745j&Ei?CT-HXlWqwlb=Lu{$5kF2~>55S{4Q^mw z0t>+GBsQ4%ZzQn~sp+50W{|`0CbJ#H{#6QVrxJL(D+?vi(v79cwX;_bmP2D*??ESB znVx-mun08YWCN-5uQ%Bw8fk1#c0elIqMy_fkM?6()O7C8wn5VT0c-&Q3kR?-h#_tu zMLG%L?Q*CpKJCHWF?}GjR!=tt$i+@Y+$3rguvP{m;sE{AXqV{_%?bqN_fl0_&4%*>z=I>eR?wn|Qk zUYSfztAm*?x2BA9Syeoa6>uX>KSPyBXl52bckT^D< zviLvv_K4^?Y$C@I^I21+K0p>0<**>>g$DR@4)YV87qRP}xOEMihcRo|6wzrdD^}r< ztR<>p{~X%(>|5AGD8zkr-Kyfm$DrYRIS_>XHnUG~*%me#mf)EQAtzPN$Ush`^@+b>kGC_Wb9=7Lt&_hJe61&)%f$Dsc~2b>t99h>1B$$k z{GkPs#iTcQuF4)P7Pg+eH+ZgpeY7^>SBa0`;sY5C^Gk2uG!TZO-xz+0*6_c^@OORL z=7pm7bpFzdJw?%HA)lzSUzUnrm-3N1%Uvu|SMi++vAV6}i5BQAdTisVa-mY zCp=G+itOmcl7H>y5?KZDX$~L&opGh;L@A7u4gI1Aa_@_$ry!A_Gcotgw44(`8vatde5K z?|qa`MBwME6w9pm!(XXGbYw>awy2~;my(?)Q5^%6licg?FDR6^WGE-ng-91sGeo&U z17J!mB?g;TCs|22xw_Ju_%2mfWMvUj!v&44AtAA?hLSHg8KNIVYpoa7rhc18c}2zI zXOUQPa&1MHV$EwSXEd_PyMaPghIqSy;wG2hVU3k9sPSr|)TE|y6B-~1%_hn&NERtg z6`JdB2qjKIM)graOXV;2a)B^gDGy!AH8oyIQ9aKsB0K7p)^TLU)ecGvt%|RmMX*_~ zE^9P9Eo1R#XA-4u*X)&SzM@UCvR$74o;s8iDv_vZfSIWZ9oI3rixL5q#D`r-4e-Ny zU6n0NEEdxR2fd5 z+&NU~$*5PCz2PEugt9~RELcI~MM|HzX6f?`<-W|FJL8pn@O&zdJ5>pJ#C6=6lcn@f zptHC+S*a(t)8J{!M-+q^)0H4xKTXMoWQ?A!^d)tu>$Xh2kMopKL~%P$=|xS4naWyH z?!ioD7B!P+DXU4V+Orju`zZ-?pijOMLhLd5$^$u#t1ePxaX4*}(wt-;T;$3vR-h~= z_Ad*RvDAbuRyt5~aS6?x@rx-a4m!)YgbZDxOqLa9$!g^~$vpeDLVJ3m7`jfWE0ccF z2IT_+JvS=v%lY4DvKlC6Z=wt&+M}D5Inuzsf@qS&NugwEq(EvB(I$#rMan8>B-!2C z)1k))i`~>3L_52K8iV`xQ+B!t?Ksk^`ihWmluu>q|MNXfm3Pk3+DHFj3Gbl>ZJf=Y*0jC;JztX~3{z*JOXMm~xXygHO9AJCWAKk4`I*rDT_g zEBlPHSq80KS30a?>*q=s?mOqQ>c%;x6({wu#dD>K>)J);S##=hAXINZzwBClW{jG?Ht1Imf|fPUb95` zhRnKELUAQ!3LhxV$~|54p)v!K#kPmaES>r~JfjqMsoM(6-f_aNst;W>KSUjbkk8cRj!E?)i+DY&JlN%yBZ2jksfp4pY_#564Ii9T7^8)zkx~@M-CAdtG1HZeofTV)HGS5wf>Z5id{`q~>mPC1`j~eCWx^Rk% zzx+7`(}QN5XJ2(L8MmUZnj?*j9-vZ%)K!dohsJ_r@xx&CiB#`Mnktj8ak}~$4O5h^ zj+STV`oq*vxw51VS1S|q$l+=|wbb2O{6zdAO%1^Pqoupi$Z*+}lA+4|@AC|`vfS`i zjaB8%LCIM4SA)PGvegxe!`;)0RlcT3#jH^R#8;El968r$iHpIvbJY|QwmFw{PR0&1 z)OQG4GednMEyz(P*o!d0rhP@pex zy1e%lFAeRU+@bHey(YP2)##IvcxKh!m4lFU`fi1*JYG}edlH2|ZuN8x^NE+1APK** zNkU=q*48P3Gm6P=Rmg4fimrg!l{ysy;ypTeFx;03-9)&*w$~jNi}y0M-XL03(*}Sz zQCl0&sN}%tnpza@iPk*v(`fCbWfqgAh!L*fD2L`RR>Wv@?Ys!@)Yp!A{was~wgPR% zbh}W1i{I3iia`yvk))5=(i(=38fhEJ%$2d)Ckzf_mD(@{OCGCsbKRK*xG`J{5~mWh zHyK;Pu(%TmZ_`<$!;vpuNz%e`NTTKgvoJGJTSrYql15)wB&Ly6lGdqWP5J!;t`+Vo$T>;wLHP+~Jt(&}^zL%~mSK1^YlQE_1vl*^{by;M7!&zJ`?Q zLLE|<;?&nP_qq_x&MvQMsN?m}66+a1|0MZ`Q{_fq*Zi^d8?W^Y>gp0$x9e+xmTs=D z&~BQOQlhwiTmli+lrY4* zxtUfUX5-an6a*I(j@z4SHkd6AH`f9I=HQh$tywv$WeY;(2}cX9fS31q(&aW@j?=0k zy}7ILF=@8hNEB7Yhw<7{pfvDrOIf!F`?l4xVWyN<7311zZs^{QLQ^&CF^$3!im012kngKacR>*nN>|Fd9hV5V*t)g&|0zUR=S7M zYT&`@+6E%dsG;qmhVr!q*6FJ0IJ%~`i_LK*M>yt1P<;B)gGgNYL>-;kbcW=(aID-w zQxPJyoO0~ONUgJ!;)O<(cG7dh|IKU+9H2$RLhLj^>julkk^x$*8!c0vhii8HdX&~n zIMTI$Xnzva(~=fq{3k=R3&PMbI9U)7uCY0%Ff3E6C-gqrD1epX*-LTAaV+)!2XZv6==5uX^LK1kcc2|o3Gf&$g#Zy~T6wlE%(uIV`&euM1 zBjuhi*Upi0KdsPatFTnO_ci^+hPu<&xw_l0*YW_CB6ar`(HphC2GPtA+Sma2QfMc& z%@#Qod!N%Pi=WSFbfe;n6EABug!+r*D+6|2pm3G}So@-870)kf^ml+Vbi}1s=!Q7# zvTJ^jkblcLE?uUTa^n@(N-2e->=2KyycU6deAa zt{TExR}Xb(lg@~!X8H|Ya7YXpy%j>0EJteOZ>LqDQKp!Y=z_-&8$Jw&PRvuHs^<-nJg)SCvUR z)ep%?ZJ22CnZ8@rd<29G|6KiAIc8PREL|dk=jpk`w0fRy(@Vjo_@ICcOh)SKAaWP$ ze^B<83YfoKzfdj!Nr1mt^_8CDMPYutP2W#V>R!DT{=S_)TKXavvP&EkI-R0@F>}{z ziuZO)3NdxJUW@WhY%SCm5s4t~`7#e(QY!A(>2ovI+5eg?=o?p8qiP>U6)JjOQQeb}{%*eKY}rfPDZ$EPAZhG6+8WLcj69 zE*sZ#+`x=ragG@dPjRP`@h*r6Z=)~3UHq&fL3hRNiUz2-?Wq2tI235?rwev5wT98t zleD?g(2)CFYI7r!?$Zsrbi(vjMg#PVH9jTn7R4IR}}kZ(@3agh-eiJRIInLi$FE4x-rZf9^jlwd^T zmIT9>`VS`<3)#a(;+>AhECzSPqs~TUpw>6Zh?gVwNHH42ZTgBzf2$!-q!QW>&$=4% zcdF5gv)fEA?>=I1H-r9+a2G{)qb9Lj>TYyZV6JG;%LtW0q<=hQ+Q{w4hZ@QB#UXf@ zaa+UH8AcdRnq#SiLoe{B*=6=GtS7wMq`Y|=r+cvg-CCH zCB9P{bNb|Lr!S>x>)XhWT@(Gp?_-R1fQK@Sb~sd$rj9rE)2HH!6O2LN6k{hCK7e0; zWW>TOarq;oih?yiGA4(%pl#$3^Vx^a#PdRYW+oF49$DQv|OalzdpRJLcam{-wqAeNjbdUvwa_keuN>tR^| z`J(=t7Fyntv43xioac9XTZYL^s8>IWw}m|@5W|L8Ookq5mbb}oBhxH}{}GaPDqh*< z<|A6BTfU+{z)5sC>ccFJ$hR$qSW11c-VQEK`U~Y|pYBlI{3xOLY#L z@VIHIA`VQk6nS7B(-MYf=2&`S_Y9*FE|_D9V|zJn%D05#^JW%L@wsW43piwfrHu%l zXNlxkX`v+ozg}QzN`ii0U}=c$@-1<&53}WEm?3&bT6?y*5HOn z`rGm%oDL7v#*5q_H~O#AEo@?U8%Q(@?QSIiH$Kk^cN00`)<{Eh!smFTK#asIC@Oaw))`x3D$mSjJFoysR`B?95=yg!3z_t zK6<-BV>=8QG#azBt(D!{j~(>Rn2bTmqlaMY@l=BM&9b(_C*!T{@n)8_I{uSsZH)KE zS?ME3A@NVjvJSx(6Rci%XuP!n7LK!qV5jj`KecPdz>GoIe4Mqe6dQuOCs+fpa<FZg z$U42sD{&T_Uu3O>_Y1B5(uPRfu*cf7)S3}R)|Qx1WUY*gimZWB$xvLnhm>r+$Jz$> mOX7<~WUEVYBB_W05~M-WM322zTLZX&9;P)=OnhKXAMigpO|WkO delta 11480 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 V0~T8&`n>csEP*2PiDl@3{{xO&yVC#w diff --git a/modules/artifacts/abstract_dex_adapter-osmosis.wasm b/modules/artifacts/abstract_dex_adapter-osmosis.wasm index 9d71d9d2b515950495ebfd13df3b1d681377078a..3cc5e726f2daaf0aed7efb12c7db76fde14046ef 100644 GIT binary patch delta 11319 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 U)9!YFFZsfB*mh delta 5044 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 diff --git a/modules/artifacts/abstract_money_market_adapter.wasm b/modules/artifacts/abstract_money_market_adapter.wasm index 8ba76f18fc8b6162c2c03e33284713feecaa058c..46254a25e1dee93a975bc5cf64091acec9d630fc 100644 GIT binary patch delta 4932 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 delta 5045 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 diff --git a/modules/artifacts/abstract_subscription.wasm b/modules/artifacts/abstract_subscription.wasm index bec74aabb80071d551af7025d27a76c8453623e8..9dbe7f39e6a0cdab875ac54aca0940337d7ad88e 100644 GIT binary patch delta 3629 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 delta 3620 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 diff --git a/modules/artifacts/abstract_tendermint_staking_adapter.wasm b/modules/artifacts/abstract_tendermint_staking_adapter.wasm index 29d21e2d5e86115513cf9802ce87b0d572f15b70..85d97fd305b72e609717c29a0892f7ecef5f2641 100644 GIT binary patch delta 3698 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 T>x_mWd~le-TNsI<+eiNa1<2~{ delta 3704 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 diff --git a/modules/artifacts/challenge_app.wasm b/modules/artifacts/challenge_app.wasm index 41195d05a4f9d46d7d81e1a6d6aa9e4767df61df..585789cb2f2795ff542225ebb7396dfe0abad53b 100644 GIT binary patch delta 6841 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 diff --git a/modules/artifacts/checksums.txt b/modules/artifacts/checksums.txt index 547fca5e7b..dd06bdb818 100644 --- a/modules/artifacts/checksums.txt +++ b/modules/artifacts/checksums.txt @@ -1,14 +1,18 @@ -6d7e0e435f8f7da77f76f284fbb49c5f4ee75e972dcd52e9d22faacd096eaa4b abstract_cw_staking-archway.wasm -989c8d176212284f421978e45dc6a980ac19d5ceb505e130e5c08b67338f4143 abstract_cw_staking-osmosis.wasm -1d66b3e87437b5d2a1a505c4e0420989ea018bf81f5f339478d560d4c3b84305 abstract_cw_staking.wasm -44c37e56682c80c4c27c0d10fb42ddad08624b50d4b20b7f7f69038a1a96da6f abstract_dex_adapter-archway.wasm -0c3700ab2352d026638cfa5f1391acf469ad200b1ebc78eb302c251a5e0510e2 abstract_dex_adapter-osmosis.wasm -c37222b43979be7cb1171c09896edce5922f4c041686ae2c6f421824dfaa9911 abstract_dex_adapter.wasm -15b823a589f8005d191a13aa34d9a891acf9b9cf11c0be4458ef5e12ca602b62 abstract_money_market_adapter.wasm -180ce817a7115444cca0b54317bc7ddaf1dba4e15acd1698bdd1e1735c9d3028 abstract_subscription.wasm -47d5889da5e3f7334707d427e0114f9e3e702877c6eedad59c67dbdf0749979d abstract_tendermint_staking_adapter.wasm -d6b54dd65e4c4263e7ee6104098383a278660c658d45f5c9f66a849b48b95e75 calendar_app.wasm -85719e52e1013ba9c7a2afd4bdcdf8ac57d232b51ee63b59a5d6b81c89e6499e challenge_app.wasm -81df10126fe45fc4a6cd7979ec38288a54049283b5563f4a4a2f578babdf43f4 my_standalone.wasm -e2a34cb4a6dcdadee677960ba35624a2f93aef07d8bb9cd2850f7eeba138fd8f payment_app.wasm -4a19b396456cada2c8a191b01060d21df6bb9cd14c0853b400a3965cdd72db66 ping_pong.wasm +6b4fee90e5943de7bdf154c87ba717e3eb6435c16c4efb269aba1d7f09565a0f abstract_cw_staking-archway.wasm +7900526ec3051cb9d6b8213676b1bcef2f6ea7e0e1a1d5109483bf69959a95fc abstract_cw_staking-osmosis.wasm +abdee0bb743b91334b6bf15dc6c96dbadce14ff6e22ad7d5632c9d93c349933f abstract_cw_staking.wasm +c9341249956e575b730193dabb09281c15cc01083a7635c3d152494464309a57 abstract_dex_adapter-archway.wasm +6f0462071485786281a02d2065ddbe6c700e1eb05d6d87b0dad5ddc86ee9d093 abstract_dex_adapter-osmosis.wasm +f0a32d4b4b426b3081804d1236e03ec958e6f81a8f3990dd349f58145a0cfb47 abstract_dex_adapter.wasm +b9ff47b14815def977416224f3e51acfdaa9c2ecd2f36fc2ba2811d990310252 abstract_money_market_adapter.wasm +0b3e1efed127fc5d47a96ce8f9eeff33207be1c525127723642c816585ead3ce abstract_oracle_adapter-neutron.wasm +0b3e1efed127fc5d47a96ce8f9eeff33207be1c525127723642c816585ead3ce abstract_oracle_adapter-osmosis.wasm +0b3e1efed127fc5d47a96ce8f9eeff33207be1c525127723642c816585ead3ce abstract_oracle_adapter-xion.wasm +7d453a4a492931ec3f9f17499dfe703505c6b95ef94dbccdeb03401b70556f5e abstract_oracle_adapter.wasm +800ed379a8b1f69462a2efa0e342838bd038344646d7e930f74aac43665000bf abstract_subscription.wasm +9133af28c983213a560429af8948ab17e24d4c4ee9be22e0d455b68060a5932a abstract_tendermint_staking_adapter.wasm +91cedca4035718d69fbb14b19626938d1cb736a3dd673729b2b4ed75445d711f calendar_app.wasm +d776983b7bfd1231b1cda11c054294a34a0dd92ebc48bff76b1e88b27fb5ff5b challenge_app.wasm +8f8fbf5102749b180c9b61aa7f3c66a62282bc1948d5c160fc18f95e916739d4 my_standalone.wasm +72dc6d80bac13986afd4bd4fab46b11648306c8b7b065280c377f1eadc045f48 payment_app.wasm +049f861b1656d76a8f3557f062911cdf130ffeb950922ee80061404534992d4f ping_pong.wasm diff --git a/modules/artifacts/my_standalone.wasm b/modules/artifacts/my_standalone.wasm index 1d3f3130945b73654bd40239392e5a46ccd2fef1..39d5b589757b7b2d23d4bae8dbc549c627205295 100644 GIT binary patch delta 4017 zcmYjT30#!b7N2v!@6N{vGt9^gFu2S>nM?|5E-a#gT4tJAF8LI+^Y!f+e6s8Ek_hSOry30+p}@wn8Bk z(CduR-i|^206&_?OZ1QqoiVW(R7`)7zpj^=`g)(TuVoOdUkaWI=}g+mY>!?%=NF>No;yKuoXl=>aOIoz_vhINJ26jUjX56utrwS*YyA8w z22KLnTx)Zk;Pjr&4VMhJ@&-eQ&)b#nr_Wwg;=??;E8j_YTs{SPujb#9u00E*^$vx0 zf_oOOhvVMkh2z^39I;jsf4x@DBm6a~pOLM1B^qVaYwNt!9^B;7KV0XhFI*oaP3s*% zqH04b3EjM@#bYSx#?4ZHU$)-N^6fy0J1bkv9{qY{FePr@GC)R2#_X-Zl#O|dN8h{k zGOYc))w^RuV4(Ng zx>Nq_&cs|Z& zRpMd0(ysIsB7eZmto?)-086EP;2>$o8H4Du)a#vBZ^W9RT-QhFPH)DwPl(?e|Jx=8 zv3lU2!QP**M=21ecf7Fz;=Ma=^pk7ox&4rCzio&3t)AO*?hiJHlW}Bo7iOt?m4<6F zxLJ}P&E?$!*eyrw!DvJWj%9Ef9HOfNqXAd@LwDS&LJ)+aP+?ySP|kgTm$w1uIhb&p zkxscUz}Nl72<;$L+%UpG$sXrNb-<3-rEmzZ3C8)@<7`RAMU+iDH$<`tvPs5O{*a&~ zMP^{85u&ib9|D;*3}+jmo9viT3jhl^F*v}-Xf;C*OVV~pqPig|A;TJig!P3mJQxTO zm}aIrWyee#M2L@+AY!ILFBK9*`m<1^u%*kz z&#BR=8GJM8_`31-VI4YK8LcjK+Qwg{fsKe>A;eI?Y3+@wN z6~QAQ#9}zZFku;O!YJ|dGH|=S>0V{A&1FSc$U~U5|z{Cbhz_OPI z;(`Vkgp>F3(W3Gjs0qOOw;&SdT!HzRz7u{Br+$Q0W}4Nszo6kEN3g+dh-8Kc*+`8J zne`w}=*7B;hA1{svDsQ2{m=ItK)_dVuvcCJK8oOOSYP7+Yx; zWkZ=q5!=VJsQ`^=t%s%f$vAcn8d~(zlh{|V8CMNuk7Df+dU>Wj!iI@K6IlQV(*(8! z#GA>?slWieX_N~uOl1iDMea2Al0RF&QYg=}a=GJMUtpIkC*<;UbQ_b-$nquDWwNsh zZF2TpR!5?L7UgQkWm&%76WLOT;CXC}^vPJj4v~n?VIv65&0*c?3W+yz*(>rY_0DUv zcEc%o%pao`F$dv87Wr^3UkY(NpRJ~%B&IB3TV)iHb;GD4)`70p@S?j6vBf@UY_TsY zw1hn@y{9Z?!|1S9FJ)9xnng_+Yp}2{_KBtCtRC3455yCdtT%@kQB=)V0WHUza0gc0 z#t6T*imedtCY$<88sn9}Gb-*IWmw+;f` zg#?btS57G8Nu5t!B(GH}KX)P7Sg(9&CRy=?(z}0~^RHI5mYijzOPsc=@x95z{HQw4 zpAO`VF=`hRTok3rYONnQ#bYy7-`anfqS6(`<`gxYPVT=TvgN`I2-+$1?Rc@dTBst1YcJk0pI-lw){H)xjF=#q~0E2kiweIixsH ztS0|W_^z&|!zSTcqi(ja>gD3YE$ZWpMmATeedUvx@uqs&bU&qgl@S#tZ&xQ_S&jO2 zi|KpIZuw3|wAlsOV^vdJ0Q09jYXK`as3Ev_m-=epXVUR=`NCBwlBw4YwWlc9t%Gb$)Mv)cB7x@$0wJ?4nl;G)odARttH(x?`TTq9}uMZq3QeyZx zx(&E5j#Hr)4RQRMyi%w7^J4%PaNPiY2`-4jf&52>ZQCbi4d%1xQxLx$#_5AjG!LV% zcvik&@Zr1z-1j;7->on2uzNaX%s>Rw9{`QE3N&I2JtI7Nz<@?TLK9kZ9ox+0v?;Fb>fm+NM%gc>(u`w1s@7T*E)}_|ufr=tcb1&N#Q64`u>z_D0?bGdA<*U=PA( z9vymjQ7RRGi-A53UadZ8NOFjbjr=ue^}>b?Jb_)cU~?{aWBf+m2VTGqZ^Erf2?_jSG2r7aaic( z&)oY233`I=*k~G-IzEFnny{&khvS+$9@~QT6|A0E;iRnlC1UE^d^iZ#5&o2&<~+B7 zPvf@MjA(D$()q55(+5_O=yZke3xt(;_AfpiR*HlhdlJ>GO{(RjeEwa1xm?Lh*{+*$_N z2@h`HY8Q#UHSVO&BO|q`B&tVhV_Ft&w41y6Jqu@kT^^{t(=|Irrf6euU#iv#qjqR9vN2(C ziWY<`(#VfoBJp^t7K@Y8v;f?bru9O1sTP4F(zS6Im8My+DNTD6wN%o4v3Y4UF$!~Q zkEf^3r36G(x>o4GU1?fx85)8E3$!q-EzmqzUZ92BXUu;nK7Poo%%ojg-wc@D%1NSuo1^@s6 delta 4195 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 delta 4427 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 diff --git a/modules/artifacts/ping_pong.wasm b/modules/artifacts/ping_pong.wasm index 4a075955a08381b408a10cee7c58d5d79d5266c4..69efd118c6096c230fa05524cc24bc360cd206a1 100644 GIT binary patch delta 4026 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 delta 3997 zcmYjTd0f=h7WdrW@BV%R!@!Kdu!8WCj}Q^P|SoXQpWiW-rkM5m9qjS`1Y3 zXC4JaT=2P(=nuFIB5s+xrDVp-vb4-4w?xdI`ri4?$kX}b_dVy_v)y~nJ$D}NYV~ke zt1@5~lO)TsRW@;xtg4zfTQ8YpuI*-BSu;iZjdf%o>vpLP^U$DG9;|>abF@SrF@Nr7 zunacA%;iu5i(ox$fQ>Ng{du$JFNDpo6}G{45a5J8Pz5zm4c&&HhOgi(=+X(2R>8L< z{RWQ1*KiI_LLHoeQ}6*Gtb+6KJ#@Q4%w4zzzr#(KTL*u_eRvG_;9JS?=7ek(;{=W6 zu@!79%VEn{w<;K32g8@L zab6D79IM-DFKbI7Q2V+tnkbX@NV5|cRM=JPw{kJ59bXy5o-P*^n>2s4L9o^qE1$}e z(4_gSHe{_<8?qpm8&A!=W*+VJlQqj2gpkm!-iPSpEBomq*M=HCv(`0vS+~xly;W@2 z+F(1asQ5O8UADedBIs3;L7?s2a*@8vxBkGc6zWs94K=I}>}U->+LGPjnyIu5d~|1N z5^YNxysN#|eWx$9)c&@!<|!XjX7Gt+Zoa1$x2w5pr8h})cReC{$?mfhZL~hzaPhdj zr*^&EP!964zekc)w^@2kueTjMZJn8BmpTBH0-Q@b?0F7Gg_gA4&cU+igbjK$@ z?qJvR^_~~Y+I;DH4cJW<&!I6Eh%x&iT>Lc$o&bd4!+GR81cTW@RT(A0k!p46)VPDxdXBc>i+SMnyugzGG1+=Jl!W+6Zd;d;MeNFh zG?nsgwHoFDCg(#09$W+KC|k-Q9JBKw$dI{4;J;Wu=arWdb2A+PGI@6m@<&{l0@|YRt};lku3nRZ7};7 zL|A`T2%^httSx5`)`>U&!3wemN zsq@(q8x3~xD32`)HI^2XGN%ITL|i#jCBi;}T>`>LC!56#XT^J1QXpHpUi?wVj&XYR z#NK*l0($Snk$*E^A1J`@ud#^)iPu>=6k+9cHWFXG&TPVQgN@@*hzswqHwmma*ccIa zmlgR@vh`egC!C5OA0^#j2Ma|?Ib^78;g*1O2vu}Qa;^% z(eVW-jKO9xsEbr(g8vHsl2mVWsbPX-;w9wXQZXpytLbj`z?f)hD-Mg7I??Ry<6SMjBIQ z*idOVyS`Sa!=&~q)QYa7q_8k(z@amxBxn#DXG+ri_#mYYn3%5sdVZurGWE(A#i+W;~IrBH_G&P$t^wDC58x;IUp3Jh3iM0R7 z4YJrIaSy<2z}w?);IUXL6XnNvtp88O{c|{&qgg^=s{0Dw@etz}e-&_&nJ`?If)iD^rDZgc9jT^o3mh$`l*{GQA9 zyo7tp`BAJBJX)-%;0a7T5}aOy2F!Kx5!9-`IQbL1+CZgoQKFt}avjSq^LF^r zuY9jxo>7}9Dx^aH2i=9t6K`DMS>Bp_Yo)07R6GGsH}GQjfG;4R+1?Yk+~@Il_#z~U zx<)?E26@=cq>Lw6ZBjk5$`|pm?mBYB(FG+M7RJ z7fBiF!$4vN=BQ%{w&ke9+((w=;12%Wk=b(9+_pHkQuV;3O0^@d)zt_ruB12wWde<&^szMFNE9GhoCReGxriAqLVVTL96Y#dKhGEMJ^-bRy zUE<>UrcKGrNFJa0`h<*W6Vs;P!E&`V-mY*vPsR;ZY5+biS6{%iDwShorE0^wCscp@ z=!6=KXDZc&7(vqN_BW<&Pty!EiNu`N)~=AR0pOCbu#v;QU&g)P`xp& zT=npp@LqZ*rJZPi=;TyiZH{S` anyhow::Result<()> { - let rt = Runtime::new()?; - let version: Version = CONTRACT_VERSION.parse().unwrap(); - let chain = DaemonBuilder::new(network).handle(rt.handle()).build()?; - let oracle = OracleAdapter::new(chain); - oracle.deploy(version, Empty {}, DeployStrategy::Try)?; +fn deploy_oracle(networks: Vec) -> anyhow::Result<()> { + // run for each requested network + for network in networks { + let version: Version = CONTRACT_VERSION.parse().unwrap(); + let chain = DaemonBuilder::new(network).build()?; + let oracle = OracleAdapter::new(chain); + oracle.deploy(version, Empty {}, DeployStrategy::Try)?; + } Ok(()) } use clap::Parser; -use tokio::runtime::Runtime; #[derive(Parser, Default, Debug)] #[command(author, version, about, long_about = None)] struct Arguments { /// Network Id to deploy on - #[arg(short, long)] - network_id: String, + #[arg(short, long, value_delimiter = ' ', num_args = 1..)] + network_ids: Vec, } fn main() -> anyhow::Result<()> { - dotenv().ok(); + dotenv::dotenv()?; env_logger::init(); - use dotenv::dotenv; - let args = Arguments::parse(); + let networks = args + .network_ids + .iter() + .map(|n| parse_network(n).unwrap()) + .collect(); - let network = parse_network(&args.network_id).unwrap(); - - deploy_oracle(network) + deploy_oracle(networks) } diff --git a/modules/contracts/adapters/oracle/examples/register_ans.rs b/modules/contracts/adapters/oracle/examples/register_ans.rs new file mode 100644 index 0000000000..4b3f58dc5b --- /dev/null +++ b/modules/contracts/adapters/oracle/examples/register_ans.rs @@ -0,0 +1,51 @@ +use abstract_adapter::objects::UncheckedContractEntry; +use abstract_interface::{Abstract, ExecuteMsgFns}; +use abstract_oracle_adapter::interface::deployment::pyth_addresses; +use abstract_pyth_adapter::PYTH; +use cw_orch::daemon::networks::parse_network; +use cw_orch::prelude::*; + +fn deploy_oracle(networks: Vec) -> anyhow::Result<()> { + // run for each requested network + for network in networks { + let chain = DaemonBuilder::new(network.clone()).build()?; + let abstr = Abstract::load_from(chain.clone())?; + + // This works only for PYTH, we have to find a better logic for other oracles and adapters + abstr.ans_host.update_contract_addresses( + vec![( + UncheckedContractEntry { + protocol: PYTH.to_string(), + contract: "oracle".to_string(), + }, + pyth_addresses().get(network.chain_id).unwrap().to_string(), + )], + vec![], + )?; + } + Ok(()) +} + +use clap::Parser; + +#[derive(Parser, Default, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + /// Network Id to deploy on + #[arg(short, long, value_delimiter = ' ', num_args = 1..)] + network_ids: Vec, +} + +fn main() -> anyhow::Result<()> { + dotenv::dotenv()?; + env_logger::init(); + + let args = Arguments::parse(); + let networks = args + .network_ids + .iter() + .map(|n| parse_network(n).unwrap()) + .collect(); + + deploy_oracle(networks) +} diff --git a/modules/contracts/adapters/oracle/examples/schema.rs b/modules/contracts/adapters/oracle/examples/schema.rs index 28517216f9..e67e790f4f 100644 --- a/modules/contracts/adapters/oracle/examples/schema.rs +++ b/modules/contracts/adapters/oracle/examples/schema.rs @@ -1,6 +1,6 @@ use std::{env::current_dir, fs::create_dir_all}; -use abstract_dex_adapter::{contract::DexAdapter, msg::SimulateSwapResponse}; +use abstract_oracle_adapter::contract::OracleAdapter; use cosmwasm_schema::{export_schema_with_title, remove_schemas, schema_for}; fn main() { @@ -9,10 +9,5 @@ fn main() { create_dir_all(&out_dir).unwrap(); remove_schemas(&out_dir).unwrap(); - DexAdapter::export_schema(&out_dir); - export_schema_with_title( - &schema_for!(SimulateSwapResponse), - &out_dir, - "AdapterResponse", - ); + OracleAdapter::export_schema(&out_dir); } diff --git a/modules/contracts/adapters/oracle/src/contract.rs b/modules/contracts/adapters/oracle/src/contract.rs index f91d1502b3..24083a0d80 100644 --- a/modules/contracts/adapters/oracle/src/contract.rs +++ b/modules/contracts/adapters/oracle/src/contract.rs @@ -11,8 +11,8 @@ pub type OracleResult = Result; pub const ORACLE_ADAPTER: OracleAdapter = OracleAdapter::new(ORACLE_ADAPTER_ID, CONTRACT_VERSION, None) - // .with_instantiate(handlers::instantiate_handler) - // .with_execute(handlers::execute_handler) + .with_instantiate(handlers::instantiate_handler) + .with_execute(handlers::execute_handler) .with_query(handlers::query_handler); #[cfg(feature = "export")] diff --git a/modules/contracts/adapters/oracle/src/lib.rs b/modules/contracts/adapters/oracle/src/lib.rs index 154a4f86fb..63405edca7 100644 --- a/modules/contracts/adapters/oracle/src/lib.rs +++ b/modules/contracts/adapters/oracle/src/lib.rs @@ -87,4 +87,35 @@ pub mod interface { Ok(vec![]) } } + + pub mod deployment { + use cosmwasm_std::Addr; + use cw_orch::daemon::networks::{NEUTRON_1, OSMOSIS_1, OSMO_5, PION_1, XION_TESTNET_1}; + use std::collections::HashMap; + + pub fn pyth_addresses() -> HashMap { + vec![ + (XION_TESTNET_1.chain_id, PYTH_XION_TEST_ADDRESS), + (PION_1.chain_id, PYTH_PION_ADDRESS), + (OSMO_5.chain_id, PYTH_OSMO_TEST_ADDRESS), + (NEUTRON_1.chain_id, PYTH_NEUTRON_ADDRESS), + (OSMOSIS_1.chain_id, PYTH_OSMOSIS_ADDRESS), + ] + .into_iter() + .map(|(key, value)| (key.to_string(), Addr::unchecked(value))) + .collect() + } + + pub const PYTH_XION_TEST_ADDRESS: &str = + "xion1w39ctwxxhxxc2kxarycjxj9rndn65gf8daek7ggarwh3rq3zl0lqqllnmt"; + pub const PYTH_PION_ADDRESS: &str = + "neutron15ldst8t80982akgr8w8ekcytejzkmfpgdkeq4xgtge48qs7435jqp87u3t"; + pub const PYTH_OSMO_TEST_ADDRESS: &str = + "osmo1hpdzqku55lmfmptpyj6wdlugqs5etr6teqf7r4yqjjrxjznjhtuqqu5kdh"; + + pub const PYTH_NEUTRON_ADDRESS: &str = + "neutron1m2emc93m9gpwgsrsf2vylv9xvgqh654630v7dfrhrkmr5slly53spg85wv"; + pub const PYTH_OSMOSIS_ADDRESS: &str = + "osmo13ge29x4e2s63a8ytz2px8gurtyznmue4a69n5275692v3qn3ks8q7cwck7"; + } } diff --git a/modules/contracts/adapters/oracle/src/oracle_tester.rs b/modules/contracts/adapters/oracle/src/oracle_tester.rs index 7ce32252c4..f1069a4773 100644 --- a/modules/contracts/adapters/oracle/src/oracle_tester.rs +++ b/modules/contracts/adapters/oracle/src/oracle_tester.rs @@ -1,8 +1,5 @@ use crate::{interface::OracleAdapter, ORACLE_ADAPTER_ID}; -use abstract_adapter::abstract_interface::{ - AdapterDeployer, DeployStrategy, MFactoryQueryFns, RegistryExecFns, -}; -use abstract_adapter::std::ans_host::QueryMsgFns; +use abstract_adapter::abstract_interface::{AdapterDeployer, DeployStrategy, RegistryExecFns}; use abstract_adapter::std::objects::module::{ModuleInfo, ModuleVersion}; use abstract_client::{AbstractClient, Environment}; @@ -32,6 +29,7 @@ pub struct OracleTester> { } impl> OracleTester { + /// Used to test new code pub fn new(abstr_deployment: AbstractClient, oracle: Oracle) -> anyhow::Result { // Re-register dex, to make sure it's latest let _ = abstr_deployment @@ -57,6 +55,22 @@ impl> OracleTester { }) } + /// Used to test on-chain code + pub fn new_live( + abstr_deployment: AbstractClient, + oracle: Oracle, + ) -> anyhow::Result { + let account = abstr_deployment.account_builder().build()?; + let oracle_adapter = + account.install_adapter::>(&[])?; + + Ok(Self { + abstr_deployment, + oracle_adapter: oracle_adapter.module()?, + oracle, + }) + } + pub fn test_price(&self) -> anyhow::Result { // Get the price associated with the ID self.oracle_adapter diff --git a/modules/contracts/adapters/oracle/src/oracles/mod.rs b/modules/contracts/adapters/oracle/src/oracles/mod.rs index ea26142127..6ae1194072 100644 --- a/modules/contracts/adapters/oracle/src/oracles/mod.rs +++ b/modules/contracts/adapters/oracle/src/oracles/mod.rs @@ -1,17 +1,7 @@ -use abstract_oracle_standard::{Identify, OracleCommand, OracleError}; +use abstract_oracle_standard::{OracleCommand, OracleError}; pub use abstract_pyth_adapter::PYTH; -/// Any exchange should be identified by the adapter -/// This allows erroring the execution before sending any IBC message to another chain -/// This provides superior UX in case of an IBC execution -pub(crate) fn identify_oracle(value: &str) -> Result, OracleError> { - match value { - abstract_pyth_adapter::PYTH => Ok(Box::::default()), - _ => Err(OracleError::UnknownDex(value.to_owned())), - } -} - pub(crate) fn resolve_oracle(value: &str) -> Result, OracleError> { match value { #[cfg(feature = "pyth")] diff --git a/modules/justfile b/modules/justfile index bcd6777056..d44ebf6ec5 100644 --- a/modules/justfile +++ b/modules/justfile @@ -62,4 +62,4 @@ deploy-to-all-chains: publish-schemas: SCHEMA_OUT_DIR=$(cd ../../schemas && echo "$PWD") \ - cargo ws exec --no-bail bash -lc 'cargo schema && { jq -r .contract_version schema/module-schema.json > _version.txt; outdir="$SCHEMA_OUT_DIR/abstract/${PWD##*/}/$(cat _version.txt)"; mkdir -p "$outdir"; rm -rf "schema/raw"; cp -a "schema/." "$outdir"; rm _version.txt; }' + cargo ws exec --no-bail bash -lc 'cargo schema && { jq -r .contract_version schema/module-schema.json > _version.txt; outdir="$SCHEMA_OUT_DIR/abstract/${PWD##*/}/$(cat _version.txt)"; mkdir -p "$outdir"; rm -rf "schema/raw"; cp -a "schema/." "$outdir"; rm _version.txt; }' \ No newline at end of file diff --git a/scripts/wasm-all.sh b/scripts/wasm-all.sh index 5ad2a6e09c..3d1cec434e 100755 --- a/scripts/wasm-all.sh +++ b/scripts/wasm-all.sh @@ -9,18 +9,18 @@ fi starting_dir=$(pwd) -echo "Wasming framework" -cd ./framework +# echo "Wasming framework" +# cd ./framework -# Delete all the current wasms first -rm -rf ./artifacts/*.wasm -# Optimized builds -docker run --rm -v "$(pwd)":/code \ - --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ - --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - ${image} +# # Delete all the current wasms first +# rm -rf ./artifacts/*.wasm +# # Optimized builds +# docker run --rm -v "$(pwd)":/code \ +# --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ +# --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ +# ${image} -cd $starting_dir +# cd $starting_dir echo "Wasming apps" cd ./modules From 88b02d76e4b2e5abb08036cc648cbb7d96344a77 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Tue, 26 Nov 2024 13:08:45 +0000 Subject: [PATCH 05/21] Readme --- modules/contracts/adapters/oracle/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/contracts/adapters/oracle/README.md b/modules/contracts/adapters/oracle/README.md index f4ea726a2e..48d51e04d8 100644 --- a/modules/contracts/adapters/oracle/README.md +++ b/modules/contracts/adapters/oracle/README.md @@ -10,7 +10,9 @@ The Oracle Adapter allows developers to query a price associated with a price so pub enum OracleQueryMsg{ Price{ oracle: String, - price_source_key: String + price_source_key: String, + // Only successful if price is not too old + max_age: u64 } } // And returns From 5c4486a3cf8378aab3b28740a2e7bd820fe39ee7 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Tue, 26 Nov 2024 15:29:16 +0000 Subject: [PATCH 06/21] rEMOVE TESTING for oracle --- .../packages/standards/oracle/Cargo.toml | 1 - .../packages/standards/oracle/src/lib.rs | 2 - .../packages/standards/oracle/src/tests.rs | 41 ------------------- 3 files changed, 44 deletions(-) delete mode 100644 framework/packages/standards/oracle/src/tests.rs diff --git a/framework/packages/standards/oracle/Cargo.toml b/framework/packages/standards/oracle/Cargo.toml index 8d694244c7..7c06e50db0 100644 --- a/framework/packages/standards/oracle/Cargo.toml +++ b/framework/packages/standards/oracle/Cargo.toml @@ -17,7 +17,6 @@ crate-type = ["cdylib", "rlib"] [features] default = ["export"] export = [] -testing = ["cw-orch/daemon", "abstract-interface/testing"] # Keep as is until TendermintStake updates. [dependencies] diff --git a/framework/packages/standards/oracle/src/lib.rs b/framework/packages/standards/oracle/src/lib.rs index 1f4168173e..e341caaed6 100644 --- a/framework/packages/standards/oracle/src/lib.rs +++ b/framework/packages/standards/oracle/src/lib.rs @@ -2,8 +2,6 @@ mod command; mod error; pub mod msg; -#[cfg(feature = "testing")] -pub mod tests; // Export interface for use in SDK modules pub use abstract_adapter_utils::{coins_in_assets, cw_approve_msgs, Identify}; diff --git a/framework/packages/standards/oracle/src/tests.rs b/framework/packages/standards/oracle/src/tests.rs deleted file mode 100644 index 2db1155e0d..0000000000 --- a/framework/packages/standards/oracle/src/tests.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::fmt::Debug; - -use crate::msg::PriceResponse; -use cosmwasm_std::StdError; -use cw_orch::daemon::live_mock::mock_dependencies; -use cw_orch::prelude::*; - -use crate::{OracleCommand, OracleError}; - -pub struct OracleCommandTester { - chain: ChainInfoOwned, - adapter: Box, -} - -pub fn expect_eq(t1: T, t2: T) -> Result<(), StdError> { - if t1 != t2 { - Err(StdError::generic_err(format!( - "Test failed, wrong result, expected : {:?}, got : {:?}", - t1, t2 - )))? - } - Ok(()) -} - -impl OracleCommandTester { - pub fn new(chain: ChainInfoOwned, module: T) -> Self { - Self { - chain, - adapter: Box::new(module), - } - } - - pub fn test_query_price(&self, price_source_key: String) -> Result { - let deps = mock_dependencies(self.chain.clone()); - let ans_host = todo!(); - let price_response = self - .adapter - .price(deps.as_ref(), ans_host, price_source_key)?; - Ok(price_response) - } -} From 84f8b4e14205b4966428a0385fbd9d9a878576ec Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 27 Nov 2024 07:53:15 +0000 Subject: [PATCH 07/21] Revert wasm alll script comments --- scripts/wasm-all.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/scripts/wasm-all.sh b/scripts/wasm-all.sh index 3d1cec434e..5ad2a6e09c 100755 --- a/scripts/wasm-all.sh +++ b/scripts/wasm-all.sh @@ -9,18 +9,18 @@ fi starting_dir=$(pwd) -# echo "Wasming framework" -# cd ./framework +echo "Wasming framework" +cd ./framework -# # Delete all the current wasms first -# rm -rf ./artifacts/*.wasm -# # Optimized builds -# docker run --rm -v "$(pwd)":/code \ -# --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ -# --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ -# ${image} +# Delete all the current wasms first +rm -rf ./artifacts/*.wasm +# Optimized builds +docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + ${image} -# cd $starting_dir +cd $starting_dir echo "Wasming apps" cd ./modules From bd220aec8c7a846eec4d0a93c1afd48b5b6ead0e Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 27 Nov 2024 07:55:09 +0000 Subject: [PATCH 08/21] Revert just file --- modules/justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/justfile b/modules/justfile index d44ebf6ec5..bcd6777056 100644 --- a/modules/justfile +++ b/modules/justfile @@ -62,4 +62,4 @@ deploy-to-all-chains: publish-schemas: SCHEMA_OUT_DIR=$(cd ../../schemas && echo "$PWD") \ - cargo ws exec --no-bail bash -lc 'cargo schema && { jq -r .contract_version schema/module-schema.json > _version.txt; outdir="$SCHEMA_OUT_DIR/abstract/${PWD##*/}/$(cat _version.txt)"; mkdir -p "$outdir"; rm -rf "schema/raw"; cp -a "schema/." "$outdir"; rm _version.txt; }' \ No newline at end of file + cargo ws exec --no-bail bash -lc 'cargo schema && { jq -r .contract_version schema/module-schema.json > _version.txt; outdir="$SCHEMA_OUT_DIR/abstract/${PWD##*/}/$(cat _version.txt)"; mkdir -p "$outdir"; rm -rf "schema/raw"; cp -a "schema/." "$outdir"; rm _version.txt; }' From eff065fd3020b36162abe63d1e27ed58a9949a4d Mon Sep 17 00:00:00 2001 From: Kayanski <44806566+Kayanski@users.noreply.github.com> Date: Wed, 27 Nov 2024 08:56:18 +0100 Subject: [PATCH 09/21] Update framework/packages/standards/oracle/README.md Co-authored-by: Interchain Adair <32375605+adairrr@users.noreply.github.com> --- framework/packages/standards/oracle/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/packages/standards/oracle/README.md b/framework/packages/standards/oracle/README.md index e0b4c3fb6e..2c1e3ce41f 100644 --- a/framework/packages/standards/oracle/README.md +++ b/framework/packages/standards/oracle/README.md @@ -1,5 +1,5 @@ -# Dex Adapter Trait +# Oracle Adapter Trait -A trait that defines a standard interface for Dex interactions. This trait should be implemented for each Dex that the adapter supports. +A trait that defines a standard interface for Oracle interactions. This trait should be implemented for each Oracle that the adapter supports. -To implement this trait, create a new package, import this crate and implement the trait for your Dex. +To implement this trait, create a new package, import this crate and implement the trait for your Oracle. From 961972bee2a689cf48ac65b0ff9093a974e91661 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 27 Nov 2024 08:00:13 +0000 Subject: [PATCH 10/21] remove dex references inside oracle --- .../packages/standards/oracle/src/command.rs | 4 +- .../packages/standards/oracle/src/error.rs | 27 ++----- .../packages/standards/oracle/src/msg.rs | 6 +- integrations/Cargo.toml | 77 +++++++++---------- .../adapters/oracle/src/oracles/mod.rs | 2 +- 5 files changed, 50 insertions(+), 66 deletions(-) diff --git a/framework/packages/standards/oracle/src/command.rs b/framework/packages/standards/oracle/src/command.rs index 8665affe41..a78e627c67 100644 --- a/framework/packages/standards/oracle/src/command.rs +++ b/framework/packages/standards/oracle/src/command.rs @@ -6,9 +6,9 @@ use crate::error::OracleError; use crate::msg::{PriceResponse, Seconds}; /// # OracleCommand -/// ensures DEX adapters support the expected functionality. +/// ensures Oracle adapters support the expected functionality. /// -/// Implements the usual DEX operations. +/// Implements the usual Oracle operations. pub trait OracleCommand: Identify { /// Return oracle price given pair id fn price( diff --git a/framework/packages/standards/oracle/src/error.rs b/framework/packages/standards/oracle/src/error.rs index 7ab9fb43b2..c5e036d7f6 100644 --- a/framework/packages/standards/oracle/src/error.rs +++ b/framework/packages/standards/oracle/src/error.rs @@ -1,9 +1,6 @@ use abstract_adapter::AdapterError; use abstract_sdk::AbstractSdkError; -use abstract_std::{ - objects::{ans_host::AnsHostError, DexAssetPairing}, - AbstractError, -}; +use abstract_std::{objects::ans_host::AnsHostError, AbstractError}; use cosmwasm_std::StdError; use cw_asset::AssetError; use thiserror::Error; @@ -28,11 +25,11 @@ pub enum OracleError { #[error(transparent)] AnsHostError(#[from] AnsHostError), - #[error("DEX {0} is not a known dex on this network.")] - UnknownDex(String), + #[error("Oracle {0} is not a known oracle on this network.")] + UnknownOracle(String), - #[error("DEX {0} is not local to this network.")] - ForeignDex(String), + #[error("Oracle {0} is not local to this network.")] + ForeignOracle(String), #[error("Asset type: {0} is unsupported.")] UnsupportedAssetType(String), @@ -46,24 +43,12 @@ pub enum OracleError { #[error("Provided asset {0} not in pool with assets {1:?}.")] ArgumentMismatch(String, Vec), - #[error("Balancer pool not supported for dex {0}.")] - BalancerNotSupported(String), - - #[error("Pair {0} on DEX {1} does not match with pair address {2}")] - DexMismatch(String, String, String), - - #[error("Not implemented for dex {0}")] + #[error("Not implemented for oracle {0}")] NotImplemented(String), - #[error("Maximum spread {0} exceeded for dex {1}")] - MaxSlippageAssertion(String, String), - #[error("Message generation for IBC queries not supported.")] IbcMsgQuery, - #[error("Asset pairing {} not found.", asset_pairing)] - AssetPairingNotFound { asset_pairing: DexAssetPairing }, - #[error("Invalid Generate Message")] InvalidGenerateMessage, diff --git a/framework/packages/standards/oracle/src/msg.rs b/framework/packages/standards/oracle/src/msg.rs index 2896469932..fefc6add32 100644 --- a/framework/packages/standards/oracle/src/msg.rs +++ b/framework/packages/standards/oracle/src/msg.rs @@ -1,11 +1,11 @@ #![warn(missing_docs)] -//! # Dex Adapter API +//! # Oracle Adapter API // re-export response types use abstract_std::adapter; use cosmwasm_schema::QueryResponses; use cosmwasm_std::{Decimal, Empty}; -/// The name of the dex to trade on. +/// The name of the oracle to query prices from. pub type OracleName = String; /// Top-level Abstract Adapter execute message. This is the message that is passed to the `execute` entrypoint of the smart-contract. @@ -17,7 +17,7 @@ pub type QueryMsg = adapter::QueryMsg; impl adapter::AdapterQueryMsg for OracleQueryMsg {} -/// Query messages for the dex adapter +/// Query messages for the oracle adapter #[cosmwasm_schema::cw_serde] #[derive(QueryResponses, cw_orch::QueryFns)] pub enum OracleQueryMsg { diff --git a/integrations/Cargo.toml b/integrations/Cargo.toml index 9849f25f8e..e79ee4623b 100644 --- a/integrations/Cargo.toml +++ b/integrations/Cargo.toml @@ -28,56 +28,55 @@ version = "0.25.0" [workspace.dependencies] cosmwasm-schema = { version = "2.0" } -cosmwasm-std = { version = "2.0" } +cosmwasm-std = { version = "2.0" } cw-address-like = { version = "2.0" } -cw-asset = { version = "4.0" } -cw-controllers = "2.0" -cw-orch = { version = "0.27.0" } -cw-ownable = { version = "2.0" } -cw-plus-orch = { version = "0.25.0" } +cw-asset = { version = "4.0" } +cw-controllers = "2.0" +cw-orch = { version = "0.27.0" } +cw-ownable = { version = "2.0" } +cw-plus-orch = { version = "0.25.0" } cw-storage-plus = "2.0.0" -cw-utils = "2.0" -cw2 = "2.0.0" -cw20 = { version = "2.0.0" } -cw20-base = { version = "2.0.0" } +cw-utils = "2.0" +cw2 = "2.0.0" +cw20 = { version = "2.0.0" } +cw20-base = { version = "2.0.0" } anyhow = "1.0" -chrono = { version = "0.4.31", default-features = false } -clap = { version = "4.0.32", features = ["derive"] } -protobuf = { version = "2", features = ["with-bytes"] } -schemars = "0.8" -semver = "1.0" -serde = { version = "1.0", default-features = false, features = ["derive"] } +chrono = { version = "0.4.31", default-features = false } +clap = { version = "4.0.32", features = ["derive"] } +protobuf = { version = "2", features = ["with-bytes"] } +schemars = "0.8" +semver = "1.0" +serde = { version = "1.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.50" } ## crates in order of publishing ## see docs/Publishing.md -abstract-adapter = { version = "0.25.0" } +abstract-adapter = { version = "0.25.0" } abstract-interface = { version = "0.25.0" } -abstract-sdk = { version = "0.25.0" } -abstract-std = { version = "0.25.0" } +abstract-sdk = { version = "0.25.0" } +abstract-std = { version = "0.25.0" } -abstract-adapter-utils = { version = "0.25.0" } -abstract-dex-standard = { version = "0.25.0" } +abstract-adapter-utils = { version = "0.25.0" } +abstract-dex-standard = { version = "0.25.0" } abstract-money-market-standard = { version = "0.25.0" } -abstract-oracle-standard = { version = "0.25.0" } -abstract-staking-standard = { version = "0.25.0" } +abstract-oracle-standard = { version = "0.25.0" } +abstract-staking-standard = { version = "0.25.0" } -# TODO: REMOVE As soon as new dex-standard published [patch.crates-io] abstract-macros = { path = "../framework/packages/abstract-macros" } -abstract-sdk = { path = "../framework/packages/abstract-sdk" } -abstract-std = { path = "../framework/packages/abstract-std" } +abstract-sdk = { path = "../framework/packages/abstract-sdk" } +abstract-std = { path = "../framework/packages/abstract-std" } -abstract-adapter = { path = "../framework/packages/abstract-adapter" } +abstract-adapter = { path = "../framework/packages/abstract-adapter" } abstract-interface = { path = "../framework/packages/abstract-interface" } -abstract-adapter-utils = { path = "../framework/packages/standards/utils" } -abstract-dex-standard = { path = "../framework/packages/standards/dex" } +abstract-adapter-utils = { path = "../framework/packages/standards/utils" } +abstract-dex-standard = { path = "../framework/packages/standards/dex" } abstract-money-market-standard = { path = "../framework/packages/standards/money-market" } -abstract-oracle-standard = { path = "../framework/packages/standards/oracle" } -abstract-staking-standard = { path = "../framework/packages/standards/staking" } +abstract-oracle-standard = { path = "../framework/packages/standards/oracle" } +abstract-staking-standard = { path = "../framework/packages/standards/staking" } # In case polytone not released # abstract-polytone = { git = "https://github.com/AbstractSDK/polytone.git", branch = "bump/cw2" } @@ -86,12 +85,12 @@ abstract-staking-standard = { path = "../framework/packages/standards/staki # Backup release profile, will result in warnings during optimization [profile.release] -codegen-units = 1 -debug = false +codegen-units = 1 +debug = false debug-assertions = false -incremental = false -lto = true -opt-level = 3 -overflow-checks = true -panic = 'abort' -rpath = false +incremental = false +lto = true +opt-level = 3 +overflow-checks = true +panic = 'abort' +rpath = false diff --git a/modules/contracts/adapters/oracle/src/oracles/mod.rs b/modules/contracts/adapters/oracle/src/oracles/mod.rs index 6ae1194072..d945c90786 100644 --- a/modules/contracts/adapters/oracle/src/oracles/mod.rs +++ b/modules/contracts/adapters/oracle/src/oracles/mod.rs @@ -6,6 +6,6 @@ pub(crate) fn resolve_oracle(value: &str) -> Result, Orac match value { #[cfg(feature = "pyth")] abstract_pyth_adapter::PYTH => Ok(Box::::default()), - _ => Err(OracleError::ForeignDex(value.to_owned())), + _ => Err(OracleError::ForeignOracle(value.to_owned())), } } From 1fe48ec5e917579b73826aa676ff68a138a7c14a Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 27 Nov 2024 08:06:15 +0000 Subject: [PATCH 11/21] remove dex references inside oracle --- integrations/oracles/pyth/src/lib.rs | 2 +- modules/contracts/adapters/oracle/README.md | 7 + modules/contracts/adapters/oracle/STATUS.md | 12 +- modules/contracts/adapters/oracle/src/api.rs | 6 +- .../adapters/oracle/src/oracle_tester.rs | 4 +- .../adapters/oracle/tests/common/mod.rs | 52 -- .../adapters/oracle/tests/osmosis.rs | 486 ------------------ .../contracts/adapters/oracle/tests/raw.rs | 172 ------- .../contracts/adapters/oracle/tests/swap.rs | 211 -------- 9 files changed, 17 insertions(+), 935 deletions(-) delete mode 100644 modules/contracts/adapters/oracle/tests/common/mod.rs delete mode 100644 modules/contracts/adapters/oracle/tests/osmosis.rs delete mode 100644 modules/contracts/adapters/oracle/tests/raw.rs delete mode 100644 modules/contracts/adapters/oracle/tests/swap.rs diff --git a/integrations/oracles/pyth/src/lib.rs b/integrations/oracles/pyth/src/lib.rs index a467941c29..d75b81b3d3 100644 --- a/integrations/oracles/pyth/src/lib.rs +++ b/integrations/oracles/pyth/src/lib.rs @@ -26,7 +26,7 @@ use { pub const XION_TEST: &str = "xion1w39ctwxxhxxc2kxarycjxj9rndn65gf8daek7ggarwh3rq3zl0lqqllnmt"; #[cfg(feature = "full_integration")] -/// Osmosis app-chain dex implementation +/// Pyth oracle implementation impl OracleCommand for Pyth { fn price( &self, diff --git a/modules/contracts/adapters/oracle/README.md b/modules/contracts/adapters/oracle/README.md index 48d51e04d8..f89df66b5c 100644 --- a/modules/contracts/adapters/oracle/README.md +++ b/modules/contracts/adapters/oracle/README.md @@ -76,6 +76,13 @@ The Oracle Adapter ensures that your application remains flexible. If a new orac - **Safer Applications**: Build applications that leverage multiple oracles simultaneously, offering users more stability and safety for their asset value. - **Future-Proofing**: Ensure your application remains compatible with future oracles that emerge in the Cosmos ecosystem. +## Tests + +Tests for this implementation can be found in different locations: + +- Either inside this crate for tests that can be run inside Mock or OsmosisTestTube +- In the `/interchain/modules-clone-testing` crate for integrations that require CloneTesting (e.g. Pyth)? + ## Documentation - **Oracle Interface**: For a detailed look at the oracle interface, refer to the [Rust trait interface](https://github.com/AbstractSDK/abstract/blob/bcf26f2f446478fd2825de5b187321dc9a626341/modules/contracts/adapters/oracle/src/api.rs#L38). diff --git a/modules/contracts/adapters/oracle/STATUS.md b/modules/contracts/adapters/oracle/STATUS.md index c258a9e2ad..1aab8c7a41 100644 --- a/modules/contracts/adapters/oracle/STATUS.md +++ b/modules/contracts/adapters/oracle/STATUS.md @@ -1,11 +1,7 @@ # Adapter Status -This document describes the status of the dex adapter's integrations with different external systems. +This document describes the status of the oracle adapter's integrations with different external systems. -| Protocol | Implementation | Execution Tests | Query Tests | Routing | Notes | -| --- | --- | --- | --- | --- | --- | -| Osmosis | ✅ | ✅ | ❌ | ✅ | | -| Astroport | ✅ | ✅ | ✅ | ✅ | | -| Wynd | ✅ | ✅ | ❌ | ❌ | | -| Bow | ✅ | ❌ | ✅ | ❌ | Liquidity tests not implemented because it uses custom module. | -| Astrovault | ✅ | ✅ | ✅ | ❌ | Testing: Astrovault uses custom archway module to create pool, so we rely on existing pools for testing. | +| Protocol | Implementation | Execution Tests | Query Tests | Notes | +| --- | --- | --- | --- | --- | +| Pyth | ✅ | --- | ✅ | diff --git a/modules/contracts/adapters/oracle/src/api.rs b/modules/contracts/adapters/oracle/src/api.rs index 47e96dd8d2..bf40ba8cd5 100644 --- a/modules/contracts/adapters/oracle/src/api.rs +++ b/modules/contracts/adapters/oracle/src/api.rs @@ -9,11 +9,11 @@ use abstract_oracle_standard::msg::{OracleQueryMsg, PriceResponse}; use cosmwasm_std::Deps; // API for Abstract SDK users -/// Interact with the dex adapter in your module. +/// Interact with the oracle adapter in your module. pub trait OracleInterface: AccountIdentification + Dependencies + ModuleIdentification + AbstractNameService { - /// Construct a new dex interface. + /// Construct a new oracle interface. fn oracle<'a>(&'a self, deps: Deps<'a>, name: OracleName) -> Oracle { Oracle { base: self, @@ -36,7 +36,7 @@ pub struct Oracle<'a, T: OracleInterface> { } impl<'a, T: OracleInterface> Oracle<'a, T> { - /// returns DEX name + /// returns Oracle name pub fn oracle_name(&self) -> OracleName { self.name.clone() } diff --git a/modules/contracts/adapters/oracle/src/oracle_tester.rs b/modules/contracts/adapters/oracle/src/oracle_tester.rs index f1069a4773..b086e0f8b4 100644 --- a/modules/contracts/adapters/oracle/src/oracle_tester.rs +++ b/modules/contracts/adapters/oracle/src/oracle_tester.rs @@ -11,7 +11,7 @@ use cw_orch::anyhow; pub trait MockOracle { const MAX_AGE: u64; - /// Name of the dex + /// Name of the oracle fn name(&self) -> String; /// First asset @@ -31,7 +31,7 @@ pub struct OracleTester> { impl> OracleTester { /// Used to test new code pub fn new(abstr_deployment: AbstractClient, oracle: Oracle) -> anyhow::Result { - // Re-register dex, to make sure it's latest + // Re-register oracle adapter, to make sure it's latest let _ = abstr_deployment .registry() .remove_module(ModuleInfo::from_id( diff --git a/modules/contracts/adapters/oracle/tests/common/mod.rs b/modules/contracts/adapters/oracle/tests/common/mod.rs deleted file mode 100644 index 69e1f4ae0c..0000000000 --- a/modules/contracts/adapters/oracle/tests/common/mod.rs +++ /dev/null @@ -1,52 +0,0 @@ -use abstract_adapter::std::objects::gov_type::GovernanceDetails; -use abstract_interface::{AbstractAccount, AccountFactory}; -use cw_orch::{environment::Environment, prelude::*}; -pub fn create_default_account( - factory: &AccountFactory, -) -> anyhow::Result> { - let os = factory.create_default_account(GovernanceDetails::Monarchy { - monarch: Addr::unchecked(factory.environment().sender_addr()).to_string(), - })?; - Ok(os) -} - -// /// Instantiates the dex adapter and registers it with the registry -// #[allow(dead_code)] -// pub fn init_dex_adapter( -// chain: Mock, -// deployment: &Abstract, -// version: Option, -// ) -> anyhow::Result> { -// let mut dex_adapter = DexAdapter::new(EXCHANGE, chain); -// dex_adapter -// .as_instance_mut() -// .set_mock(Box::new(boot_core::ContractWrapper::new_with_empty( -// ::dex::contract::execute, -// ::dex::contract::instantiate, -// ::dex::contract::query, -// ))); -// dex_adapter.upload()?; -// dex_adapter.instantiate( -// &InstantiateMsg::{ -// app: DexInstantiateMsg{ -// swap_fee: Decimal::percent(1), -// recipient_os: 0, -// }, -// base: abstract_adapter::std::adapter::BaseInstantiateMsg { -// ans_host_address: deployment.ans_host.addr_str()?, -// registry_address: deployment.registry.addr_str()?, -// }, -// }, -// None, -// None, -// )?; - -// let version: Version = version -// .unwrap_or_else(|| deployment.version.to_string()) -// .parse()?; - -// deployment -// .registry -// .register_adapters(vec![dex_adapter.as_instance()], &version)?; -// Ok(dex_adapter) -// } diff --git a/modules/contracts/adapters/oracle/tests/osmosis.rs b/modules/contracts/adapters/oracle/tests/osmosis.rs deleted file mode 100644 index dcce8d301f..0000000000 --- a/modules/contracts/adapters/oracle/tests/osmosis.rs +++ /dev/null @@ -1,486 +0,0 @@ -#![cfg(feature = "osmosis-test")] - -use std::{format, rc::Rc}; - -use abstract_adapter::std::{ - ans_host::ExecuteMsgFns, - objects::{ - gov_type::GovernanceDetails, pool_id::PoolAddressBase, AnsAsset, AssetEntry, PoolMetadata, - }, -}; -use abstract_dex_adapter::{ - contract::CONTRACT_VERSION, - interface::DexAdapter, - msg::{DexInstantiateMsg, SwapNode}, - DEX_ADAPTER_ID, -}; -use abstract_dex_standard::ans_action::DexAnsAction; -use abstract_interface::{ - Abstract, AbstractInterfaceError, AccountI, AdapterDeployer, AnsHost, DeployStrategy, -}; -use abstract_osmosis_adapter::OSMOSIS; -use anyhow::Result as AnyResult; -use cosmwasm_std::{coin, coins, Decimal, Uint128}; -use cw_asset::AssetBase; -use cw_orch::prelude::*; -use cw_orch_osmosis_test_tube::{osmosis_test_tube::Account, OsmosisTestTube}; - -/// Provide liquidity using Abstract's OS (registered in daemon_state). -pub fn provide( - dex_adapter: &DexAdapter, - asset1: (&str, u128), - asset2: (&str, u128), - dex: String, - os: &AccountI, - ans_host: &AnsHost, -) -> Result<(), AbstractInterfaceError> { - let asset_entry1 = AssetEntry::new(asset1.0); - let asset_entry2 = AssetEntry::new(asset2.0); - - dex_adapter.ans_action( - dex, - DexAnsAction::ProvideLiquidity { - assets: vec![ - AnsAsset::new(asset_entry1, asset1.1), - AnsAsset::new(asset_entry2, asset2.1), - ], - max_spread: Some(Decimal::percent(30)), - }, - os, - ans_host, - )?; - Ok(()) -} - -/// Withdraw liquidity using Abstract's OS (registered in daemon_state). -pub fn withdraw( - dex_adapter: &DexAdapter, - lp_token: &str, - amount: impl Into, - dex: String, - os: &AccountI, - ans_host: &AnsHost, -) -> Result<(), AbstractInterfaceError> { - let lp_token = AnsAsset::new(lp_token, amount.into()); - - dex_adapter.ans_action( - dex, - DexAnsAction::WithdrawLiquidity { lp_token }, - os, - ans_host, - )?; - Ok(()) -} - -fn get_pool_token(id: u64) -> String { - format!("gamm/pool/{}", id) -} - -#[allow(clippy::type_complexity)] -fn setup_mock() -> anyhow::Result<( - OsmosisTestTube, - DexAdapter, - AccountI, - Abstract, - u64, -)> { - let atom = "uatom"; - let osmo = "uosmo"; - let juno = "ujunox"; - - let chain = OsmosisTestTube::new(vec![ - coin(1_000_000_000_000, atom), - coin(1_000_000_000_000, juno), - coin(1_000_000_000_000, osmo), - ]); - - let deployment = Abstract::deploy_on(chain.clone(), ())?; - - let _root_os = AccountI::create_default_account( - &deployment, - GovernanceDetails::Monarchy { - monarch: chain.sender_addr().to_string(), - }, - )?; - let dex_adapter = DexAdapter::new(DEX_ADAPTER_ID, chain.clone()); - - dex_adapter.deploy( - CONTRACT_VERSION.parse()?, - DexInstantiateMsg { - swap_fee: Decimal::percent(1), - recipient_account: 0, - }, - DeployStrategy::Try, - )?; - - // We need to register some pairs and assets on the ans host contract - - let pool_id = - chain.create_pool(vec![coin(10_000_000_000, osmo), coin(10_000_000_000, atom)])?; - - deployment - .ans_host - .update_asset_addresses( - vec![ - ("atom".to_string(), cw_asset::AssetInfoBase::native(atom)), - ("osmo".to_string(), cw_asset::AssetInfoBase::native(osmo)), - ( - "osmosis/atom,osmo".to_string(), - cw_asset::AssetInfoBase::native(get_pool_token(pool_id)), - ), - ], - vec![], - ) - .unwrap(); - - deployment - .ans_host - .update_dexes(vec![OSMOSIS.into()], vec![]) - .unwrap(); - - deployment - .ans_host - .update_pools( - vec![( - PoolAddressBase::id(pool_id), - PoolMetadata::constant_product( - OSMOSIS, - vec!["osmo".to_string(), "atom".to_string()], - ), - )], - vec![], - ) - .unwrap(); - - let account = AccountI::create_default_account( - &deployment, - GovernanceDetails::Monarchy { - monarch: chain.sender_addr().to_string(), - }, - )?; - - // install DEX_ADAPTER_ID on OS - account.install_adapter(&dex_adapter, &[])?; - - Ok((chain, dex_adapter, account, deployment, pool_id)) -} - -#[test] -fn swap() -> AnyResult<()> { - // We need to deploy a Testube pool - let (chain, dex_adapter, os, abstr, _pool_id) = setup_mock()?; - - let account_addr = os.address()?; - - let swap_value = 1_000_000_000u128; - - chain.bank_send(account_addr.to_string(), coins(swap_value, "uatom"))?; - - // Before swap, we need to have 0 uosmo and swap_value uatom - let balances = chain.query_all_balances(&account_addr)?; - assert_eq!(balances, coins(swap_value, "uatom")); - // swap 100_000 uatom to uosmo - dex_adapter.ans_swap( - ("atom", swap_value), - "osmo", - OSMOSIS.into(), - &os, - &abstr.ans_host, - )?; - - // Assert balances - let balances = chain.query_all_balances(&account_addr)?; - assert_eq!(balances.len(), 1); - let balance = chain.query_balance(&account_addr, "uosmo")?; - assert!(balance > Uint128::zero()); - - Ok(()) -} - -#[test] -fn swap_concentrated_liquidity() -> AnyResult<()> { - // We need to deploy a Testube pool - let (chain, dex_adapter, os, deployment, _pool_id) = setup_mock()?; - - let account_addr = os.address()?; - - let swap_value = 1_000_000_000u128; - - chain.bank_send(account_addr.to_string(), coins(swap_value, "uatom"))?; - - let lp = "osmosis/osmo2,atom2"; - let pool_id = chain.create_pool(vec![coin(1_000, "uosmo"), coin(1_000, "uatom")])?; - - deployment - .ans_host - .update_asset_addresses( - vec![ - ( - "osmo2".to_string(), - cw_asset::AssetInfoBase::native("uosmo"), - ), - ( - "atom2".to_string(), - cw_asset::AssetInfoBase::native("uatom"), - ), - ( - lp.to_string(), - cw_asset::AssetInfoBase::native(get_pool_token(pool_id)), - ), - ], - vec![], - ) - .unwrap(); - deployment - .ans_host - .update_pools( - vec![( - PoolAddressBase::id(pool_id), - PoolMetadata::concentrated_liquidity( - OSMOSIS, - vec!["osmo2".to_string(), "atom2".to_string()], - ), - )], - vec![], - ) - .unwrap(); - - // Before swap, we need to have 0 uosmo and swap_value uatom - let balances = chain.query_all_balances(&account_addr)?; - assert_eq!(balances, coins(swap_value, "uatom")); - // swap 100_000 uatom to uosmo - dex_adapter.ans_swap( - ("atom2", swap_value), - "osmo2", - OSMOSIS.into(), - &os, - &deployment.ans_host, - )?; - - // Assert balances - let balances = chain.query_all_balances(&account_addr)?; - assert_eq!(balances.len(), 1); - let balance = chain.query_balance(&account_addr, "uosmo")?; - assert!(balance > Uint128::zero()); - - Ok(()) -} - -#[test] -fn provide_liquidity_two_sided() -> AnyResult<()> { - // We need to deploy a Testube pool - let (chain, dex_adapter, os, abstr, pool_id) = setup_mock()?; - - let account_addr = os.address()?; - - let provide_value = 1_000_000_000u128; - - // Before providing, we need to have no assets in the account - let balances = chain.query_all_balances(&account_addr)?; - assert!(balances.is_empty()); - chain.bank_send(account_addr.to_string(), coins(provide_value * 2, "uatom"))?; - chain.bank_send(account_addr.to_string(), coins(provide_value * 2, "uosmo"))?; - - // provide to the pool - provide( - &dex_adapter, - ("atom", provide_value), - ("osmo", provide_value), - OSMOSIS.into(), - &os, - &abstr.ans_host, - )?; - - // provide to the pool reversed - provide( - &dex_adapter, - // reversed denoms - ("osmo", provide_value), - ("atom", provide_value), - OSMOSIS.into(), - &os, - &abstr.ans_host, - )?; - - // After providing, we need to get the liquidity token - let balances = chain.query_all_balances(&account_addr)?; - assert_eq!( - balances, - coins( - 10_000_000_000_000_000_000 + 9_999_999_999_999_999_990, - get_pool_token(pool_id) - ) - ); - - Ok(()) -} - -#[test] -fn provide_liquidity_one_sided() -> AnyResult<()> { - // We need to deploy a Testube pool - let (chain, dex_adapter, os, abstr, pool_id) = setup_mock()?; - - let account_addr = os.address()?; - - let provide_value = 1_000_000_000u128; - - // Before providing, we need to have no assets in the account - let balances = chain.query_all_balances(&account_addr)?; - assert!(balances.is_empty()); - chain.bank_send(account_addr.to_string(), coins(provide_value, "uatom"))?; - chain.bank_send(account_addr.to_string(), coins(provide_value, "uosmo"))?; - - // provide to the pool - provide( - &dex_adapter, - ("atom", provide_value), - ("osmo", 0), - OSMOSIS.into(), - &os, - &abstr.ans_host, - )?; - - // provide to the pool reversed - provide( - &dex_adapter, - // reversed denoms - ("osmo", provide_value), - ("atom", 0), - OSMOSIS.into(), - &os, - &abstr.ans_host, - )?; - - // After providing, we need to get the liquidity token - let balances = chain.query_all_balances(&account_addr)?; - let lp_balance = balances - .iter() - .find(|c| c.denom == get_pool_token(pool_id)) - .unwrap(); - assert!(lp_balance.amount.u128() > 9_000_000_000_000_000_000); - - Ok(()) -} - -#[test] -fn withdraw_liquidity() -> AnyResult<()> { - // We need to deploy a Testube pool - let (chain, dex_adapter, os, abstr, pool_id) = setup_mock()?; - - let account_addr = os.address()?; - - let provide_value = 1_000_000_000u128; - - // Before providing, we need to have no assets in the account - let balances = chain.query_all_balances(&account_addr)?; - assert!(balances.is_empty()); - chain.bank_send(account_addr.to_string(), coins(provide_value, "uatom"))?; - chain.bank_send(account_addr.to_string(), coins(provide_value, "uosmo"))?; - - // provide to the pool - provide( - &dex_adapter, - ("atom", provide_value), - ("osmo", provide_value), - OSMOSIS.into(), - &os, - &abstr.ans_host, - )?; - - // After providing, we need to get the liquidity token - let balance = chain.query_balance(&account_addr, &get_pool_token(pool_id))?; - - // withdraw from the pool - withdraw( - &dex_adapter, - "osmosis/atom,osmo", - balance / Uint128::from(2u128), - OSMOSIS.into(), - &os, - &abstr.ans_host, - )?; - - // After withdrawing, we should get some tokens in return and have some lp token left - let balances = chain.query_all_balances(&account_addr)?; - assert_eq!(balances.len(), 3); - - Ok(()) -} - -#[test] -fn swap_route() -> AnyResult<()> { - // We need to deploy a Testube pool - let (chain, dex_adapter, os, abstr, pool_id_atom_osmo) = setup_mock()?; - let juno = "ujunox"; - let osmo = "uosmo"; - - let pool_id_osmo_juno = - chain.create_pool(vec![coin(10_000_000_000, osmo), coin(10_000_000_000, juno)])?; - - abstr - .ans_host - .update_asset_addresses( - vec![ - ("osmo".to_string(), cw_asset::AssetInfoBase::native(osmo)), - ("juno".to_string(), cw_asset::AssetInfoBase::native(juno)), - ( - "osmosis/osmo,juno".to_string(), - cw_asset::AssetInfoBase::native(get_pool_token(pool_id_osmo_juno)), - ), - ], - vec![], - ) - .unwrap(); - - abstr - .ans_host - .update_pools( - vec![( - PoolAddressBase::id(pool_id_osmo_juno), - PoolMetadata::constant_product( - OSMOSIS, - vec!["osmo".to_string(), "juno".to_string()], - ), - )], - vec![], - ) - .unwrap(); - - let account_addr = os.address()?; - - let swap_value = 1_000_000_000u128; - - chain.bank_send(account_addr.to_string(), coins(swap_value, "uatom"))?; - - // Before swap, we need to have 0 uosmo and swap_value uatom - let balances = chain.query_all_balances(&account_addr)?; - assert_eq!(balances, coins(swap_value, "uatom")); - // swap 100_000 uatom to uosmo - dex_adapter.raw_action( - OSMOSIS.to_string(), - abstract_dex_adapter::msg::DexAction::RouteSwap { - route: vec![ - SwapNode { - pool_id: PoolAddressBase::Id(pool_id_atom_osmo), - ask_asset: cw_asset::AssetInfoBase::Native("uosmo".to_owned()), - }, - SwapNode { - pool_id: PoolAddressBase::Id(pool_id_osmo_juno), - ask_asset: cw_asset::AssetInfoBase::Native(juno.to_owned()), - }, - ], - offer_asset: AssetBase::native("uatom", swap_value), - max_spread: None, - belief_price: None, - }, - &os, - )?; - - // Assert balances - let balances = chain.query_all_balances(&account_addr)?; - assert_eq!(balances.len(), 1); - let balance = chain.query_balance(&account_addr, juno)?; - assert!(balance > Uint128::zero()); - - Ok(()) -} diff --git a/modules/contracts/adapters/oracle/tests/raw.rs b/modules/contracts/adapters/oracle/tests/raw.rs deleted file mode 100644 index 826f21e9b1..0000000000 --- a/modules/contracts/adapters/oracle/tests/raw.rs +++ /dev/null @@ -1,172 +0,0 @@ -#![cfg(feature = "TODO: replace wyndex_bundle")] - -use abstract_adapter::std::{ - adapter::AdapterRequestMsg, - ans_host::QueryMsgFns as _, - objects::{PoolAddress, ABSTRACT_ACCOUNT_ID}, -}; -use abstract_dex_adapter::{contract::CONTRACT_VERSION, msg::DexInstantiateMsg, DEX_ADAPTER_ID}; -use abstract_dex_standard::msg::DexExecuteMsg; -use abstract_interface::{AdapterDeployer, DeployStrategy}; -use cw20::msg::Cw20ExecuteMsgFns as _; -use cw20_base::msg::QueryMsgFns as _; -use cw_asset::{AssetBase, AssetInfoBase}; -mod common; -use abstract_dex_adapter::interface::DexAdapter; -use abstract_dex_standard::action::DexAction; -use abstract_interface::{Abstract, AbstractAccount}; -use common::create_default_account; -use cosmwasm_std::{coin, Decimal}; -use cw_orch::prelude::*; -use wyndex_bundle::{EUR, USD, WYNDEX as WYNDEX_WITHOUT_CHAIN, WYNDEX_OWNER}; - -const WYNDEX: &str = "cosmos-testnet>wyndex"; - -#[allow(clippy::type_complexity)] -fn setup_mock() -> anyhow::Result<( - MockBech32, - wyndex_bundle::WynDex, - DexAdapter, - AbstractAccount, - Abstract, -)> { - let chain = MockBech32::new("mock"); - let sender = chain.sender_addr(); - let deployment = Abstract::deploy_on(chain.clone(), sender.to_string())?; - let wyndex = wyndex_bundle::WynDex::deploy_on(chain.clone(), Empty {})?; - - let _root_os = create_default_account(&deployment.account_factory)?; - let dex_adapter = DexAdapter::new(DEX_ADAPTER_ID, chain.clone()); - - dex_adapter.deploy( - CONTRACT_VERSION.parse()?, - DexInstantiateMsg { - swap_fee: Decimal::percent(1), - recipient_account: ABSTRACT_ACCOUNT_ID.seq(), - }, - DeployStrategy::Try, - )?; - - let account = create_default_account(&deployment.account_factory)?; - - // mint to account - chain.set_balance(&account.address()?, vec![coin(10_000, EUR)])?; - // install exchange on OS - account.install_adapter(&dex_adapter, None)?; - - Ok((chain, wyndex, dex_adapter, account, deployment)) -} - -#[test] -fn raw_swap_native() -> anyhow::Result<()> { - let (chain, wyndex, dex_adapter, os, abstr) = setup_mock()?; - let account_addr = os.account.address()?; - - let pools = abstr.ans_host.pool_list(None, None, None)?; - println!("{:?}", pools); - - // swap 100 EUR to USD - dex_adapter.raw_swap_native( - (EUR, 100), - USD, - WYNDEX.into(), - &os, - PoolAddress::contract(wyndex.eur_usd_pair).into(), - )?; - - // check balances - let eur_balance = chain.query_balance(&account_addr, EUR)?; - assert_that!(eur_balance.u128()).is_equal_to(9_900); - - let usd_balance = chain.query_balance(&account_addr, USD)?; - assert_that!(usd_balance.u128()).is_equal_to(98); - - // assert that OS 0 received the swap fee - let os0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) - .account - .address()?; - - let os0_eur_balance = chain.query_balance(&os0_account, EUR)?; - - assert_that!(os0_eur_balance.u128()).is_equal_to(1); - - Ok(()) -} - -#[test] -fn raw_swap_native_without_chain() -> anyhow::Result<()> { - let (chain, wyndex, dex_adapter, os, abstr) = setup_mock()?; - let account_addr = os.account.address()?; - - // swap 100 EUR to USD - dex_adapter.raw_swap_native( - (EUR, 100), - USD, - WYNDEX_WITHOUT_CHAIN.into(), - &os, - PoolAddress::contract(wyndex.eur_usd_pair).into(), - )?; - - // check balances - let balances = chain.query_all_balances(&account_addr)?; - println!("{:?}", balances); - let eur_balance = chain.query_balance(&account_addr, EUR)?; - assert_that!(eur_balance.u128()).is_equal_to(9_900); - - let usd_balance = chain.query_balance(&account_addr, USD)?; - assert_that!(usd_balance.u128()).is_equal_to(98); - - // assert that OS 0 received the swap fee - let os0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) - .account - .address()?; - let os0_eur_balance = chain.query_balance(&os0_account, EUR)?; - assert_that!(os0_eur_balance.u128()).is_equal_to(1); - - Ok(()) -} - -#[test] -fn raw_swap_raw() -> anyhow::Result<()> { - let (chain, wyndex, _, os, abstr) = setup_mock()?; - let account_addr = os.account.address()?; - - // transfer raw - let owner = chain.addr_make(WYNDEX_OWNER); - wyndex - .raw_token - .call_as(&owner) - .transfer(10_000u128, account_addr.to_string())?; - - // swap 100 RAW to EUR - let swap_msg = abstract_dex_adapter::msg::ExecuteMsg::Module(AdapterRequestMsg { - account_address: None, - request: DexExecuteMsg::Action { - dex: WYNDEX.to_owned(), - action: DexAction::Swap { - offer_asset: AssetBase::cw20(wyndex.raw_token.address()?.to_string(), 100u128), - ask_asset: AssetInfoBase::native(EUR), - pool: PoolAddress::contract(wyndex.raw_eur_pair).into(), - max_spread: Some(Decimal::percent(30)), - belief_price: None, - }, - }, - }); - os.account.execute_on_module(DEX_ADAPTER_ID, swap_msg)?; - - // check balances - let raw_balance = wyndex.raw_token.balance(account_addr.to_string())?; - assert_that!(raw_balance.balance.u128()).is_equal_to(9_900); - - let eur_balance = chain.query_balance(&account_addr, EUR)?; - assert_that!(eur_balance.u128()).is_equal_to(10098); - - // assert that OS 0 received the swap fee - let account0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) - .account - .address()?; - let os0_raw_balance = wyndex.raw_token.balance(account0_account.to_string())?; - assert_that!(os0_raw_balance.balance.u128()).is_equal_to(1); - - Ok(()) -} diff --git a/modules/contracts/adapters/oracle/tests/swap.rs b/modules/contracts/adapters/oracle/tests/swap.rs deleted file mode 100644 index 318e2f915a..0000000000 --- a/modules/contracts/adapters/oracle/tests/swap.rs +++ /dev/null @@ -1,211 +0,0 @@ -#![cfg(feature = "TODO: replace wyndex_bundle")] - -use abstract_adapter::std::{ans_host::QueryMsgFns as _, objects::ABSTRACT_ACCOUNT_ID}; -use abstract_dex_adapter::{contract::CONTRACT_VERSION, msg::DexInstantiateMsg, DEX_ADAPTER_ID}; -use abstract_dex_standard::{msg::DexFeesResponse, DexError}; -use abstract_interface::{AbstractInterfaceError, AdapterDeployer, DeployStrategy}; -use cw20::msg::Cw20ExecuteMsgFns as _; -use cw20_base::msg::QueryMsgFns as _; -mod common; - -use abstract_dex_adapter::interface::DexAdapter; -use abstract_interface::{Abstract, AbstractAccount}; -use common::create_default_account; -use cosmwasm_std::{coin, Decimal}; -use cw_orch::prelude::*; -use wyndex_bundle::{EUR, RAW_TOKEN, USD, WYNDEX as WYNDEX_WITHOUT_CHAIN, WYNDEX_OWNER}; - -const WYNDEX: &str = "cosmos-testnet>wyndex"; - -#[allow(clippy::type_complexity)] -fn setup_mock() -> anyhow::Result<( - MockBech32, - wyndex_bundle::WynDex, - DexAdapter, - AbstractAccount, - Abstract, -)> { - let chain = MockBech32::new("mock"); - let sender = chain.sender_addr(); - let deployment = Abstract::deploy_on(chain.clone(), sender.to_string())?; - let wyndex = wyndex_bundle::WynDex::deploy_on(chain.clone(), Empty {})?; - - let _root_os = create_default_account(&deployment.account_factory)?; - let dex_adapter = DexAdapter::new(DEX_ADAPTER_ID, chain.clone()); - - dex_adapter.deploy( - CONTRACT_VERSION.parse()?, - DexInstantiateMsg { - swap_fee: Decimal::percent(1), - recipient_account: ABSTRACT_ACCOUNT_ID.seq(), - }, - DeployStrategy::Try, - )?; - - let account = create_default_account(&deployment.account_factory)?; - - // mint to account - chain.set_balance(&account.address()?, vec![coin(10_000, EUR)])?; - // install exchange on OS - account.install_adapter(&dex_adapter, None)?; - - Ok((chain, wyndex, dex_adapter, account, deployment)) -} - -#[test] -fn swap_native() -> anyhow::Result<()> { - let (chain, _, dex_adapter, os, abstr) = setup_mock()?; - let account_addr = os.account.address()?; - - let pools = abstr.ans_host.pool_list(None, None, None)?; - println!("{:?}", pools); - - // swap 100 EUR to USD - dex_adapter.ans_swap((EUR, 100), USD, WYNDEX.into(), &os, &abstr.ans_host)?; - - // check balances - let eur_balance = chain.query_balance(&account_addr, EUR)?; - assert_that!(eur_balance.u128()).is_equal_to(9_900); - - let usd_balance = chain.query_balance(&account_addr, USD)?; - assert_that!(usd_balance.u128()).is_equal_to(98); - - // assert that OS 0 received the swap fee - let os0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) - .account - .address()?; - - let os0_eur_balance = chain.query_balance(&os0_account, EUR)?; - - assert_that!(os0_eur_balance.u128()).is_equal_to(1); - - Ok(()) -} - -#[test] -fn swap_native_without_chain() -> anyhow::Result<()> { - let (chain, _, dex_adapter, os, abstr) = setup_mock()?; - let account_addr = os.account.address()?; - - // swap 100 EUR to USD - dex_adapter.ans_swap( - (EUR, 100), - USD, - WYNDEX_WITHOUT_CHAIN.into(), - &os, - &abstr.ans_host, - )?; - - // check balances - let eur_balance = chain.query_balance(&account_addr, EUR)?; - assert_that!(eur_balance.u128()).is_equal_to(9_900); - - let usd_balance = chain.query_balance(&account_addr, USD)?; - assert_that!(usd_balance.u128()).is_equal_to(98); - - // assert that OS 0 received the swap fee - let os0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) - .account - .address()?; - let os0_eur_balance = chain.query_balance(&os0_account, EUR)?; - assert_that!(os0_eur_balance.u128()).is_equal_to(1); - - Ok(()) -} - -#[test] -fn swap_raw() -> anyhow::Result<()> { - let (chain, wyndex, dex_adapter, os, abstr) = setup_mock()?; - let account_addr = os.account.address()?; - - // transfer raw - let owner = chain.addr_make(WYNDEX_OWNER); - wyndex - .raw_token - .call_as(&owner) - .transfer(10_000u128, account_addr.to_string())?; - - // swap 100 RAW to EUR - dex_adapter.ans_swap((RAW_TOKEN, 100), EUR, WYNDEX.into(), &os, &abstr.ans_host)?; - - // check balances - let raw_balance = wyndex.raw_token.balance(account_addr.to_string())?; - assert_that!(raw_balance.balance.u128()).is_equal_to(9_900); - - let eur_balance = chain.query_balance(&account_addr, EUR)?; - assert_that!(eur_balance.u128()).is_equal_to(10098); - - // assert that OS 0 received the swap fee - let account0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) - .account - .address()?; - let os0_raw_balance = wyndex.raw_token.balance(account0_account.to_string())?; - assert_that!(os0_raw_balance.balance.u128()).is_equal_to(1); - - Ok(()) -} - -#[test] -fn get_fees() -> anyhow::Result<()> { - let (_, _, dex_adapter, _, abstr) = setup_mock()?; - let account0_account = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID) - .account - .address()?; - - use abstract_dex_adapter::msg::DexQueryMsgFns as _; - - let fees: DexFeesResponse = dex_adapter.fees()?; - assert_eq!(fees.swap_fee.share(), Decimal::percent(1)); - assert_eq!(fees.recipient, account0_account); - Ok(()) -} - -#[test] -fn authorized_update_fee() -> anyhow::Result<()> { - let (_, _, dex_adapter, _, abstr) = setup_mock()?; - let account0 = AbstractAccount::new(&abstr, ABSTRACT_ACCOUNT_ID); - - let update_fee_msg = abstract_dex_standard::msg::ExecuteMsg::Module( - abstract_adapter::std::adapter::AdapterRequestMsg { - account_address: Some(account0.account.addr_str()?), - request: abstract_dex_standard::msg::DexExecuteMsg::UpdateFee { - swap_fee: Some(Decimal::percent(5)), - recipient_account: None, - }, - }, - ); - - dex_adapter.execute(&update_fee_msg, None)?; - - use abstract_dex_adapter::msg::DexQueryMsgFns as _; - - let fees: DexFeesResponse = dex_adapter.fees()?; - assert_eq!(fees.swap_fee.share(), Decimal::percent(5)); - Ok(()) -} - -#[test] -fn unauthorized_update_fee() -> anyhow::Result<()> { - let (_, _, _, account, _) = setup_mock()?; - - let update_fee_msg = abstract_dex_standard::msg::ExecuteMsg::Module( - abstract_adapter::std::adapter::AdapterRequestMsg { - account_address: None, - request: abstract_dex_standard::msg::DexExecuteMsg::UpdateFee { - swap_fee: Some(Decimal::percent(5)), - recipient_account: None, - }, - }, - ); - - let err = account - .account - .execute_on_module(DEX_ADAPTER_ID, update_fee_msg) - .unwrap_err(); - let AbstractInterfaceError::Orch(orch_error) = err else { - panic!("unexpected error type"); - }; - let dex_err: DexError = orch_error.downcast().unwrap(); - assert_eq!(dex_err, DexError::Unauthorized {}); - Ok(()) -} From 7ab80c98cb59be5bb07e1dccc77b7bedb5490620 Mon Sep 17 00:00:00 2001 From: Kayanski <44806566+Kayanski@users.noreply.github.com> Date: Wed, 27 Nov 2024 09:07:59 +0100 Subject: [PATCH 12/21] Update integrations/oracles/pyth/README.md Co-authored-by: Interchain Adair <32375605+adairrr@users.noreply.github.com> --- integrations/oracles/pyth/README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/integrations/oracles/pyth/README.md b/integrations/oracles/pyth/README.md index dd716ccbac..51c34af862 100644 --- a/integrations/oracles/pyth/README.md +++ b/integrations/oracles/pyth/README.md @@ -1,10 +1,15 @@ Pyth oracle is available on the following chains: -Xion Testnet -Neutron Testnet -Osmosis Mainnet -Neutron Mainnet -Osmosis Mainnet +## Testnets + +- Xion Testnet +- Neutron Testnet + +## Mainnets + +- Osmosis Mainnet +- Neutron Mainnet +- Osmosis Mainnet The available pariss can bd found under this link: https://www.pyth.network/developers/price-feed-ids#stable \ No newline at end of file From e52f504312effc1177c2192cd20b48a41973edda Mon Sep 17 00:00:00 2001 From: Buckram Date: Wed, 8 Jan 2025 13:33:26 +0200 Subject: [PATCH 13/21] bump adapter version for oracle --- framework/Cargo.lock | 4 +- .../packages/standards/oracle/Cargo.toml | 4 +- integrations/Cargo.lock | 164 ++++++++++++++- interchain/Cargo.lock | 174 +++++++++++++++- modules/Cargo.lock | 196 +++++++++++++++++- modules/contracts/adapters/oracle/src/api.rs | 2 +- 6 files changed, 517 insertions(+), 27 deletions(-) diff --git a/framework/Cargo.lock b/framework/Cargo.lock index 423d31048f..01d8e5ec94 100644 --- a/framework/Cargo.lock +++ b/framework/Cargo.lock @@ -422,7 +422,7 @@ dependencies = [ [[package]] name = "abstract-oracle-standard" -version = "0.25.0" +version = "0.26.0" dependencies = [ "abstract-adapter", "abstract-adapter-utils", @@ -440,7 +440,7 @@ dependencies = [ "cw-storage-plus", "cw20", "dotenv", - "env_logger", + "env_logger 0.11.5", "schemars", "semver", "serde", diff --git a/framework/packages/standards/oracle/Cargo.toml b/framework/packages/standards/oracle/Cargo.toml index 7c06e50db0..438a99c53c 100644 --- a/framework/packages/standards/oracle/Cargo.toml +++ b/framework/packages/standards/oracle/Cargo.toml @@ -30,13 +30,13 @@ schemars = { workspace = true } serde = { workspace = true } thiserror = { workspace = true } -abstract-adapter = { version = "0.25.0", path = "../../abstract-adapter" } +abstract-adapter = { version = "0.26.0", path = "../../abstract-adapter" } abstract-adapter-utils = { workspace = true } abstract-sdk = { workspace = true } abstract-std = { workspace = true } cw-orch = { workspace = true } -abstract-interface = { version = "0.25.0", path = "../../abstract-interface" } +abstract-interface = { version = "0.26.0", path = "../../abstract-interface" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] workspace-hack = { version = "0.1", path = "../../../workspace-hack" } diff --git a/integrations/Cargo.lock b/integrations/Cargo.lock index 0a687bc113..765bb40656 100644 --- a/integrations/Cargo.lock +++ b/integrations/Cargo.lock @@ -290,6 +290,28 @@ dependencies = [ "neutron-std", ] +[[package]] +name = "abstract-oracle-standard" +version = "0.26.0" +dependencies = [ + "abstract-adapter", + "abstract-adapter-utils", + "abstract-interface", + "abstract-sdk", + "abstract-std", + "cosmwasm-schema", + "cosmwasm-std", + "cw-address-like", + "cw-asset", + "cw-orch 0.27.0", + "cw-storage-plus", + "cw20", + "schemars", + "serde", + "thiserror", + "workspace-hack", +] + [[package]] name = "abstract-osmosis-adapter" version = "0.26.0" @@ -305,6 +327,22 @@ dependencies = [ "osmosis-std", ] +[[package]] +name = "abstract-pyth-adapter" +version = "0.26.0" +dependencies = [ + "abstract-oracle-standard", + "abstract-sdk", + "abstract-staking-standard", + "cosmwasm-schema", + "cosmwasm-std", + "cw-asset", + "cw-utils", + "cw20", + "osmosis-std", + "pyth-sdk-cw", +] + [[package]] name = "abstract-registry" version = "0.26.0" @@ -415,6 +453,17 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.11" @@ -1211,6 +1260,51 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bs58" version = "0.5.1" @@ -1871,7 +1965,7 @@ dependencies = [ "sha2 0.10.8", "thiserror", "tokio", - "toml", + "toml 0.8.19", "tonic", "uid", ] @@ -3149,6 +3243,15 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.8", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -3161,7 +3264,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash", + "ahash 0.8.11", ] [[package]] @@ -3170,7 +3273,7 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash", + "ahash 0.8.11", "allocator-api2", ] @@ -3239,6 +3342,9 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] [[package]] name = "hex-conservative" @@ -3657,7 +3763,7 @@ dependencies = [ "tiny-keccak", "tokio", "tokio-stream", - "toml", + "toml 0.8.19", "tonic", "tracing", "tracing-subscriber", @@ -4160,7 +4266,7 @@ version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b84733c0fed6085c9210b43ffb96248676c1e800d0ba38d15043275a792ffa4" dependencies = [ - "ahash", + "ahash 0.8.11", "async-broadcast", "async-stream", "async-trait", @@ -5081,6 +5187,15 @@ dependencies = [ "uint", ] +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml 0.5.11", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -5288,6 +5403,30 @@ dependencies = [ "thiserror", ] +[[package]] +name = "pyth-sdk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00bf2540203ca3c7a5712fdb8b5897534b7f6a0b6e7b0923ff00466c5f9efcb3" +dependencies = [ + "borsh", + "borsh-derive", + "hex", + "schemars", + "serde", +] + +[[package]] +name = "pyth-sdk-cw" +version = "1.2.1" +source = "git+https://github.com/lvn-hasky-dragon/pyth-crosschain?branch=update-deps#9e8a673aae1e6bf36d60b8591a6d24792ad13111" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "pyth-sdk", + "thiserror", +] + [[package]] name = "quanta" version = "0.12.3" @@ -6534,7 +6673,7 @@ dependencies = [ "serde", "serde_json", "tendermint 0.39.1", - "toml", + "toml 0.8.19", "url", ] @@ -6548,7 +6687,7 @@ dependencies = [ "serde", "serde_json", "tendermint 0.40.0", - "toml", + "toml 0.8.19", "url", ] @@ -7008,6 +7147,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.19" @@ -7783,7 +7931,7 @@ dependencies = [ name = "workspace-hack" version = "0.1.0" dependencies = [ - "ahash", + "ahash 0.8.11", "aho-corasick", "anstream", "anyhow", diff --git a/interchain/Cargo.lock b/interchain/Cargo.lock index 63d5b4b61b..986d23ebb9 100644 --- a/interchain/Cargo.lock +++ b/interchain/Cargo.lock @@ -469,6 +469,7 @@ dependencies = [ "abstract-dex-adapter", "abstract-interface", "abstract-money-market-adapter", + "abstract-oracle-adapter", "anyhow", "astrovault", "cosmwasm-std", @@ -477,7 +478,10 @@ dependencies = [ "cw-orch-clone-testing", "cw20", "env_logger 0.11.5", + "hex", "lazy_static", + "pyth-sdk-cw", + "reqwest 0.12.9", "serde", "serde_json", "tokio", @@ -527,6 +531,48 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "abstract-oracle-adapter" +version = "0.26.0" +dependencies = [ + "abstract-adapter", + "abstract-adapter-utils", + "abstract-client", + "abstract-oracle-standard", + "abstract-pyth-adapter", + "cosmwasm-schema", + "cosmwasm-std", + "cw-asset", + "cw-orch 0.27.0", + "cw-storage-plus", + "cw20", + "schemars", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "abstract-oracle-standard" +version = "0.26.0" +dependencies = [ + "abstract-adapter", + "abstract-adapter-utils", + "abstract-interface", + "abstract-sdk", + "abstract-std", + "cosmwasm-schema", + "cosmwasm-std", + "cw-address-like", + "cw-asset", + "cw-orch 0.27.0", + "cw-storage-plus", + "cw20", + "schemars", + "serde", + "thiserror 1.0.69", + "workspace-hack", +] + [[package]] name = "abstract-osmosis-adapter" version = "0.26.0" @@ -650,6 +696,22 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "abstract-pyth-adapter" +version = "0.26.0" +dependencies = [ + "abstract-oracle-standard", + "abstract-sdk", + "abstract-staking-standard", + "cosmwasm-schema", + "cosmwasm-std", + "cw-asset", + "cw-utils", + "cw20", + "osmosis-std", + "pyth-sdk-cw", +] + [[package]] name = "abstract-registry" version = "0.26.0" @@ -1695,6 +1757,51 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bs58" version = "0.5.1" @@ -2759,7 +2866,7 @@ dependencies = [ "sha2 0.10.8", "thiserror 1.0.69", "tokio", - "toml", + "toml 0.8.19", "tonic", "uuid", ] @@ -2806,7 +2913,7 @@ dependencies = [ "sha2 0.10.8", "thiserror 1.0.69", "tokio", - "toml", + "toml 0.8.19", "tonic", "uid", ] @@ -2853,7 +2960,7 @@ dependencies = [ "sha2 0.10.8", "thiserror 1.0.69", "tokio", - "toml", + "toml 0.8.19", "tonic", "uid", ] @@ -4395,6 +4502,15 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.8", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -4494,6 +4610,9 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] [[package]] name = "hex-conservative" @@ -4940,7 +5059,7 @@ dependencies = [ "tiny-keccak", "tokio", "tokio-stream", - "toml", + "toml 0.8.19", "tonic", "tracing", "tracing-subscriber", @@ -6346,6 +6465,15 @@ dependencies = [ "uint", ] +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml 0.5.11", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -6544,6 +6672,30 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pyth-sdk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00bf2540203ca3c7a5712fdb8b5897534b7f6a0b6e7b0923ff00466c5f9efcb3" +dependencies = [ + "borsh", + "borsh-derive", + "hex", + "schemars", + "serde", +] + +[[package]] +name = "pyth-sdk-cw" +version = "1.2.1" +source = "git+https://github.com/lvn-hasky-dragon/pyth-crosschain?branch=update-deps#9e8a673aae1e6bf36d60b8591a6d24792ad13111" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "pyth-sdk", + "thiserror 1.0.69", +] + [[package]] name = "quanta" version = "0.12.4" @@ -6792,6 +6944,7 @@ dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2 0.4.7", @@ -7998,7 +8151,7 @@ dependencies = [ "serde", "serde_json", "tendermint 0.39.1", - "toml", + "toml 0.8.19", "url", ] @@ -8012,7 +8165,7 @@ dependencies = [ "serde", "serde_json", "tendermint 0.40.0", - "toml", + "toml 0.8.19", "url", ] @@ -8449,6 +8602,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.19" diff --git a/modules/Cargo.lock b/modules/Cargo.lock index 0f13992f5a..db252b3512 100644 --- a/modules/Cargo.lock +++ b/modules/Cargo.lock @@ -474,6 +474,60 @@ dependencies = [ "neutron-std", ] +[[package]] +name = "abstract-oracle-adapter" +version = "0.26.0" +dependencies = [ + "abstract-adapter", + "abstract-adapter-utils", + "abstract-client", + "abstract-interface", + "abstract-oracle-adapter", + "abstract-oracle-standard", + "abstract-pyth-adapter", + "anyhow", + "bip32", + "clap 4.5.23", + "cosmwasm-schema", + "cosmwasm-std", + "cw-asset", + "cw-orch 0.27.0", + "cw-orch-osmosis-test-tube", + "cw-storage-plus", + "cw-utils", + "cw20", + "cw20-base", + "dotenv", + "env_logger 0.11.5", + "schemars", + "semver", + "serde_json", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "abstract-oracle-standard" +version = "0.26.0" +dependencies = [ + "abstract-adapter", + "abstract-adapter-utils", + "abstract-interface", + "abstract-sdk", + "abstract-std", + "cosmwasm-schema", + "cosmwasm-std", + "cw-address-like", + "cw-asset", + "cw-orch 0.27.0", + "cw-storage-plus", + "cw20", + "schemars", + "serde", + "thiserror 1.0.69", + "workspace-hack", +] + [[package]] name = "abstract-osmosis-adapter" version = "0.26.0" @@ -551,6 +605,22 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "abstract-pyth-adapter" +version = "0.26.0" +dependencies = [ + "abstract-oracle-standard", + "abstract-sdk", + "abstract-staking-standard", + "cosmwasm-schema", + "cosmwasm-std", + "cw-asset", + "cw-utils", + "cw20", + "osmosis-std 0.26.0", + "pyth-sdk-cw", +] + [[package]] name = "abstract-registry" version = "0.26.0" @@ -729,6 +799,17 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.11" @@ -1562,6 +1643,51 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bs58" version = "0.5.1" @@ -2419,7 +2545,7 @@ dependencies = [ "sha2 0.10.8", "thiserror 1.0.69", "tokio", - "toml", + "toml 0.8.19", "tonic", "uid", ] @@ -3834,6 +3960,15 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.8", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -3846,7 +3981,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash", + "ahash 0.8.11", ] [[package]] @@ -3855,7 +3990,7 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash", + "ahash 0.8.11", "allocator-api2", ] @@ -3939,6 +4074,9 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] [[package]] name = "hex-conservative" @@ -4357,7 +4495,7 @@ dependencies = [ "tiny-keccak", "tokio", "tokio-stream", - "toml", + "toml 0.8.19", "tonic", "tracing", "tracing-subscriber", @@ -4873,7 +5011,7 @@ version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b84733c0fed6085c9210b43ffb96248676c1e800d0ba38d15043275a792ffa4" dependencies = [ - "ahash", + "ahash 0.8.11", "async-broadcast", "async-stream", "async-trait", @@ -5988,6 +6126,15 @@ dependencies = [ "uint", ] +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml 0.5.11", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -6172,6 +6319,30 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "pyth-sdk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00bf2540203ca3c7a5712fdb8b5897534b7f6a0b6e7b0923ff00466c5f9efcb3" +dependencies = [ + "borsh", + "borsh-derive", + "hex", + "schemars", + "serde", +] + +[[package]] +name = "pyth-sdk-cw" +version = "1.2.1" +source = "git+https://github.com/lvn-hasky-dragon/pyth-crosschain?branch=update-deps#9e8a673aae1e6bf36d60b8591a6d24792ad13111" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "pyth-sdk", + "thiserror 1.0.69", +] + [[package]] name = "quanta" version = "0.12.4" @@ -7476,7 +7647,7 @@ dependencies = [ "serde", "serde_json", "tendermint 0.39.1", - "toml", + "toml 0.8.19", "url", ] @@ -7490,7 +7661,7 @@ dependencies = [ "serde", "serde_json", "tendermint 0.40.0", - "toml", + "toml 0.8.19", "url", ] @@ -8016,6 +8187,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.19" @@ -8802,7 +8982,7 @@ dependencies = [ name = "workspace-hack" version = "0.1.0" dependencies = [ - "ahash", + "ahash 0.8.11", "aho-corasick", "anstream", "anyhow", diff --git a/modules/contracts/adapters/oracle/src/api.rs b/modules/contracts/adapters/oracle/src/api.rs index bf40ba8cd5..96e5eb01b9 100644 --- a/modules/contracts/adapters/oracle/src/api.rs +++ b/modules/contracts/adapters/oracle/src/api.rs @@ -14,7 +14,7 @@ pub trait OracleInterface: AccountIdentification + Dependencies + ModuleIdentification + AbstractNameService { /// Construct a new oracle interface. - fn oracle<'a>(&'a self, deps: Deps<'a>, name: OracleName) -> Oracle { + fn oracle<'a>(&'a self, deps: Deps<'a>, name: OracleName) -> Oracle<'a, Self> { Oracle { base: self, deps, From c302d5ff3c87e263d65c028a6671dc186bf32f81 Mon Sep 17 00:00:00 2001 From: Kayanski <44806566+Kayanski@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:53:10 +0100 Subject: [PATCH 14/21] Update modules/contracts/adapters/oracle/src/lib.rs Co-authored-by: Mykhailo Donchenko <91957742+Buckram123@users.noreply.github.com> --- modules/contracts/adapters/oracle/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/contracts/adapters/oracle/src/lib.rs b/modules/contracts/adapters/oracle/src/lib.rs index 63405edca7..c642be05b4 100644 --- a/modules/contracts/adapters/oracle/src/lib.rs +++ b/modules/contracts/adapters/oracle/src/lib.rs @@ -105,7 +105,7 @@ pub mod interface { .map(|(key, value)| (key.to_string(), Addr::unchecked(value))) .collect() } - + Source: https://docs.pyth.network/price-feeds/contract-addresses/cosmwasm pub const PYTH_XION_TEST_ADDRESS: &str = "xion1w39ctwxxhxxc2kxarycjxj9rndn65gf8daek7ggarwh3rq3zl0lqqllnmt"; pub const PYTH_PION_ADDRESS: &str = From ed568fa90c6d1fbb906281a9be8fe346d6a325f9 Mon Sep 17 00:00:00 2001 From: Kayanski <44806566+Kayanski@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:54:36 +0100 Subject: [PATCH 15/21] Update modules/contracts/adapters/oracle/src/lib.rs Co-authored-by: Mykhailo Donchenko <91957742+Buckram123@users.noreply.github.com> --- modules/contracts/adapters/oracle/src/lib.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/contracts/adapters/oracle/src/lib.rs b/modules/contracts/adapters/oracle/src/lib.rs index c642be05b4..0eef0f511e 100644 --- a/modules/contracts/adapters/oracle/src/lib.rs +++ b/modules/contracts/adapters/oracle/src/lib.rs @@ -94,16 +94,13 @@ pub mod interface { use std::collections::HashMap; pub fn pyth_addresses() -> HashMap { - vec![ + HashMap::from([ (XION_TESTNET_1.chain_id, PYTH_XION_TEST_ADDRESS), (PION_1.chain_id, PYTH_PION_ADDRESS), (OSMO_5.chain_id, PYTH_OSMO_TEST_ADDRESS), (NEUTRON_1.chain_id, PYTH_NEUTRON_ADDRESS), (OSMOSIS_1.chain_id, PYTH_OSMOSIS_ADDRESS), - ] - .into_iter() - .map(|(key, value)| (key.to_string(), Addr::unchecked(value))) - .collect() + ]) } Source: https://docs.pyth.network/price-feeds/contract-addresses/cosmwasm pub const PYTH_XION_TEST_ADDRESS: &str = From 9a6d5e2a3a80c6c1e20fbdc38c7ecb81c2088496 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 8 Jan 2025 14:58:38 +0100 Subject: [PATCH 16/21] Remove failling code --- framework/packages/standards/oracle/src/msg.rs | 3 --- integrations/oracles/pyth/README.md | 2 +- modules/contracts/adapters/cw-staking/tests/osmosis_stake.rs | 2 +- modules/contracts/adapters/oracle/src/handlers/query.rs | 4 ---- modules/contracts/adapters/oracle/src/lib.rs | 1 - modules/contracts/adapters/oracle/src/state.rs | 4 ---- 6 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 modules/contracts/adapters/oracle/src/state.rs diff --git a/framework/packages/standards/oracle/src/msg.rs b/framework/packages/standards/oracle/src/msg.rs index fefc6add32..e8d097f601 100644 --- a/framework/packages/standards/oracle/src/msg.rs +++ b/framework/packages/standards/oracle/src/msg.rs @@ -21,9 +21,6 @@ impl adapter::AdapterQueryMsg for OracleQueryMsg {} #[cosmwasm_schema::cw_serde] #[derive(QueryResponses, cw_orch::QueryFns)] pub enum OracleQueryMsg { - /// Query the oracle adapter config - #[returns(Config)] - Config {}, /// Query the latest price attached to the price source key #[returns(PriceResponse)] Price { diff --git a/integrations/oracles/pyth/README.md b/integrations/oracles/pyth/README.md index 51c34af862..b3bd3d8d0a 100644 --- a/integrations/oracles/pyth/README.md +++ b/integrations/oracles/pyth/README.md @@ -12,4 +12,4 @@ Pyth oracle is available on the following chains: - Osmosis Mainnet -The available pariss can bd found under this link: https://www.pyth.network/developers/price-feed-ids#stable \ No newline at end of file +The available prices can be found under this link: https://www.pyth.network/developers/price-feed-ids#stable \ No newline at end of file diff --git a/modules/contracts/adapters/cw-staking/tests/osmosis_stake.rs b/modules/contracts/adapters/cw-staking/tests/osmosis_stake.rs index ead96a9d6c..ca99adc651 100644 --- a/modules/contracts/adapters/cw-staking/tests/osmosis_stake.rs +++ b/modules/contracts/adapters/cw-staking/tests/osmosis_stake.rs @@ -152,7 +152,7 @@ mod osmosis_test { AccountI, )> { std::env::set_var("RUST_LOG", "debug"); - let _ = env_logger::try_init().unwrap(); + env_logger::try_init().unwrap(); let tube = OsmosisTestTube::new(vec![ coin(1_000_000_000_000, ASSET_2), coin(1_000_000_000_000, ASSET_1), diff --git a/modules/contracts/adapters/oracle/src/handlers/query.rs b/modules/contracts/adapters/oracle/src/handlers/query.rs index d330a337ef..ee0e9613c9 100644 --- a/modules/contracts/adapters/oracle/src/handlers/query.rs +++ b/modules/contracts/adapters/oracle/src/handlers/query.rs @@ -5,7 +5,6 @@ use cosmwasm_std::{to_json_binary, Binary, Deps, Env}; use crate::contract::{OracleAdapter, OracleResult}; use crate::oracles; -use crate::state::CONFIG; pub fn query_handler( deps: Deps, @@ -14,9 +13,6 @@ pub fn query_handler( msg: OracleQueryMsg, ) -> OracleResult { match msg { - OracleQueryMsg::Config {} => { - to_json_binary(&CONFIG.load(deps.storage)?).map_err(Into::into) - } OracleQueryMsg::Price { price_source_key, oracle, diff --git a/modules/contracts/adapters/oracle/src/lib.rs b/modules/contracts/adapters/oracle/src/lib.rs index 63405edca7..ef3636becc 100644 --- a/modules/contracts/adapters/oracle/src/lib.rs +++ b/modules/contracts/adapters/oracle/src/lib.rs @@ -2,7 +2,6 @@ pub mod api; pub mod contract; pub(crate) mod handlers; pub mod oracles; -pub mod state; pub mod msg { pub use abstract_oracle_standard::msg::*; } diff --git a/modules/contracts/adapters/oracle/src/state.rs b/modules/contracts/adapters/oracle/src/state.rs deleted file mode 100644 index 159b9b77be..0000000000 --- a/modules/contracts/adapters/oracle/src/state.rs +++ /dev/null @@ -1,4 +0,0 @@ -use abstract_oracle_standard::msg::Config; -use cw_storage_plus::Item; - -pub const CONFIG: Item = Item::new("config"); From 8796f49786339acb915974de23839b28b2bcce61 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 8 Jan 2025 15:04:13 +0100 Subject: [PATCH 17/21] nits --- .../contracts/adapters/oracle/examples/register_ans.rs | 4 ++-- modules/contracts/adapters/oracle/src/lib.rs | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/contracts/adapters/oracle/examples/register_ans.rs b/modules/contracts/adapters/oracle/examples/register_ans.rs index 4b3f58dc5b..8f35898f5d 100644 --- a/modules/contracts/adapters/oracle/examples/register_ans.rs +++ b/modules/contracts/adapters/oracle/examples/register_ans.rs @@ -5,7 +5,7 @@ use abstract_pyth_adapter::PYTH; use cw_orch::daemon::networks::parse_network; use cw_orch::prelude::*; -fn deploy_oracle(networks: Vec) -> anyhow::Result<()> { +fn register_ans(networks: Vec) -> anyhow::Result<()> { // run for each requested network for network in networks { let chain = DaemonBuilder::new(network.clone()).build()?; @@ -47,5 +47,5 @@ fn main() -> anyhow::Result<()> { .map(|n| parse_network(n).unwrap()) .collect(); - deploy_oracle(networks) + register_ans(networks) } diff --git a/modules/contracts/adapters/oracle/src/lib.rs b/modules/contracts/adapters/oracle/src/lib.rs index 414faf5eab..79c841ec04 100644 --- a/modules/contracts/adapters/oracle/src/lib.rs +++ b/modules/contracts/adapters/oracle/src/lib.rs @@ -93,15 +93,18 @@ pub mod interface { use std::collections::HashMap; pub fn pyth_addresses() -> HashMap { - HashMap::from([ + [ (XION_TESTNET_1.chain_id, PYTH_XION_TEST_ADDRESS), (PION_1.chain_id, PYTH_PION_ADDRESS), (OSMO_5.chain_id, PYTH_OSMO_TEST_ADDRESS), (NEUTRON_1.chain_id, PYTH_NEUTRON_ADDRESS), (OSMOSIS_1.chain_id, PYTH_OSMOSIS_ADDRESS), - ]) + ] + .map(|(key, value)| (key.to_string(), Addr::unchecked(value))) + .into() } - Source: https://docs.pyth.network/price-feeds/contract-addresses/cosmwasm + + // Source: https://docs.pyth.network/price-feeds/contract-addresses/cosmwasm pub const PYTH_XION_TEST_ADDRESS: &str = "xion1w39ctwxxhxxc2kxarycjxj9rndn65gf8daek7ggarwh3rq3zl0lqqllnmt"; pub const PYTH_PION_ADDRESS: &str = From f9aa4a2cf0e93342abf6caf4625e6e540cccebcc Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 8 Jan 2025 15:05:45 +0100 Subject: [PATCH 18/21] Clippy --- modules/contracts/adapters/oracle/examples/schema.rs | 2 +- modules/contracts/adapters/oracle/src/api.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/contracts/adapters/oracle/examples/schema.rs b/modules/contracts/adapters/oracle/examples/schema.rs index e67e790f4f..21d48129a6 100644 --- a/modules/contracts/adapters/oracle/examples/schema.rs +++ b/modules/contracts/adapters/oracle/examples/schema.rs @@ -1,7 +1,7 @@ use std::{env::current_dir, fs::create_dir_all}; use abstract_oracle_adapter::contract::OracleAdapter; -use cosmwasm_schema::{export_schema_with_title, remove_schemas, schema_for}; +use cosmwasm_schema::remove_schemas; fn main() { let mut out_dir = current_dir().unwrap(); diff --git a/modules/contracts/adapters/oracle/src/api.rs b/modules/contracts/adapters/oracle/src/api.rs index 96e5eb01b9..316371184c 100644 --- a/modules/contracts/adapters/oracle/src/api.rs +++ b/modules/contracts/adapters/oracle/src/api.rs @@ -35,7 +35,7 @@ pub struct Oracle<'a, T: OracleInterface> { pub(crate) deps: Deps<'a>, } -impl<'a, T: OracleInterface> Oracle<'a, T> { +impl Oracle<'_, T> { /// returns Oracle name pub fn oracle_name(&self) -> OracleName { self.name.clone() From c56e58c619ff0ca26d99fa59ec5071d19661dd80 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 8 Jan 2025 15:06:53 +0100 Subject: [PATCH 19/21] Removed execution layer --- modules/contracts/adapters/oracle/src/contract.rs | 1 - .../adapters/oracle/src/handlers/execute.rs | 13 ------------- .../contracts/adapters/oracle/src/handlers/mod.rs | 2 -- 3 files changed, 16 deletions(-) delete mode 100644 modules/contracts/adapters/oracle/src/handlers/execute.rs diff --git a/modules/contracts/adapters/oracle/src/contract.rs b/modules/contracts/adapters/oracle/src/contract.rs index 24083a0d80..12bce72f5e 100644 --- a/modules/contracts/adapters/oracle/src/contract.rs +++ b/modules/contracts/adapters/oracle/src/contract.rs @@ -12,7 +12,6 @@ pub type OracleResult = Result; pub const ORACLE_ADAPTER: OracleAdapter = OracleAdapter::new(ORACLE_ADAPTER_ID, CONTRACT_VERSION, None) .with_instantiate(handlers::instantiate_handler) - .with_execute(handlers::execute_handler) .with_query(handlers::query_handler); #[cfg(feature = "export")] diff --git a/modules/contracts/adapters/oracle/src/handlers/execute.rs b/modules/contracts/adapters/oracle/src/handlers/execute.rs deleted file mode 100644 index 65f3ec38af..0000000000 --- a/modules/contracts/adapters/oracle/src/handlers/execute.rs +++ /dev/null @@ -1,13 +0,0 @@ -use cosmwasm_std::{DepsMut, Empty, Env, MessageInfo}; - -use crate::contract::{OracleAdapter, OracleResult}; - -pub fn execute_handler( - _deps: DepsMut, - _env: Env, - _info: MessageInfo, - _module: OracleAdapter, - _msg: Empty, -) -> OracleResult { - unimplemented!("No execution for this adapter") -} diff --git a/modules/contracts/adapters/oracle/src/handlers/mod.rs b/modules/contracts/adapters/oracle/src/handlers/mod.rs index b28dfdf6fc..35c6debc6c 100644 --- a/modules/contracts/adapters/oracle/src/handlers/mod.rs +++ b/modules/contracts/adapters/oracle/src/handlers/mod.rs @@ -1,7 +1,5 @@ -mod execute; mod instantiate; mod query; -pub use execute::execute_handler; pub use instantiate::instantiate_handler; pub use query::query_handler; From 7767035eafbbdbb54e9110c102c11b68a85bb814 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 8 Jan 2025 16:51:08 +0100 Subject: [PATCH 20/21] Removed unused deps --- framework/Cargo.lock | 5 --- .../packages/standards/oracle/Cargo.toml | 43 ++++++++----------- integrations/Cargo.lock | 6 --- interchain/Cargo.lock | 6 --- modules/Cargo.lock | 6 --- 5 files changed, 18 insertions(+), 48 deletions(-) diff --git a/framework/Cargo.lock b/framework/Cargo.lock index 01d8e5ec94..6bad5c8ba0 100644 --- a/framework/Cargo.lock +++ b/framework/Cargo.lock @@ -434,16 +434,11 @@ dependencies = [ "clap", "cosmwasm-schema", "cosmwasm-std", - "cw-address-like", "cw-asset", "cw-orch 0.27.0", - "cw-storage-plus", - "cw20", "dotenv", "env_logger 0.11.5", - "schemars", "semver", - "serde", "thiserror", "workspace-hack", ] diff --git a/framework/packages/standards/oracle/Cargo.toml b/framework/packages/standards/oracle/Cargo.toml index 438a99c53c..c8fdf882d2 100644 --- a/framework/packages/standards/oracle/Cargo.toml +++ b/framework/packages/standards/oracle/Cargo.toml @@ -1,13 +1,13 @@ [package] description = "The oracle adapter is a Abstract adapter for querying oracle prices. It provides a common interface for all oracles" -name = "abstract-oracle-standard" +name = "abstract-oracle-standard" authors = { workspace = true } edition = { workspace = true } license = { workspace = true } version = { workspace = true } -exclude = ["contract.wasm", "hash.txt"] +exclude = ["contract.wasm", "hash.txt"] resolver = "2" @@ -16,37 +16,30 @@ crate-type = ["cdylib", "rlib"] [features] default = ["export"] -export = [] +export = [] # Keep as is until TendermintStake updates. [dependencies] cosmwasm-schema = { workspace = true } -cosmwasm-std = { workspace = true } -cw-address-like = { workspace = true } -cw-asset = { workspace = true } -cw-storage-plus = { workspace = true } -cw20 = { workspace = true } -schemars = { workspace = true } -serde = { workspace = true } -thiserror = { workspace = true } - -abstract-adapter = { version = "0.26.0", path = "../../abstract-adapter" } -abstract-adapter-utils = { workspace = true } -abstract-sdk = { workspace = true } -abstract-std = { workspace = true } -cw-orch = { workspace = true } +cosmwasm-std = { workspace = true } +cw-asset = { workspace = true } +thiserror = { workspace = true } -abstract-interface = { version = "0.26.0", path = "../../abstract-interface" } +abstract-adapter = { version = "0.26.0", path = "../../abstract-adapter" } +abstract-adapter-utils = { workspace = true } +abstract-sdk = { workspace = true } +abstract-std = { workspace = true } +cw-orch = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] workspace-hack = { version = "0.1", path = "../../../workspace-hack" } [dev-dependencies] abstract-interface = { workspace = true, features = ["daemon"] } -abstract-sdk = { workspace = true, features = ["test-utils"] } -abstract-testing = { workspace = true } -anyhow = { workspace = true } -clap = { workspace = true } -dotenv = "0.15.0" -env_logger = "0.11.3" -semver = { workspace = true } +abstract-sdk = { workspace = true, features = ["test-utils"] } +abstract-testing = { workspace = true } +anyhow = { workspace = true } +clap = { workspace = true } +dotenv = "0.15.0" +env_logger = "0.11.3" +semver = { workspace = true } diff --git a/integrations/Cargo.lock b/integrations/Cargo.lock index 765bb40656..9a86ff7f08 100644 --- a/integrations/Cargo.lock +++ b/integrations/Cargo.lock @@ -296,18 +296,12 @@ version = "0.26.0" dependencies = [ "abstract-adapter", "abstract-adapter-utils", - "abstract-interface", "abstract-sdk", "abstract-std", "cosmwasm-schema", "cosmwasm-std", - "cw-address-like", "cw-asset", "cw-orch 0.27.0", - "cw-storage-plus", - "cw20", - "schemars", - "serde", "thiserror", "workspace-hack", ] diff --git a/interchain/Cargo.lock b/interchain/Cargo.lock index 986d23ebb9..0cf9040b74 100644 --- a/interchain/Cargo.lock +++ b/interchain/Cargo.lock @@ -557,18 +557,12 @@ version = "0.26.0" dependencies = [ "abstract-adapter", "abstract-adapter-utils", - "abstract-interface", "abstract-sdk", "abstract-std", "cosmwasm-schema", "cosmwasm-std", - "cw-address-like", "cw-asset", "cw-orch 0.27.0", - "cw-storage-plus", - "cw20", - "schemars", - "serde", "thiserror 1.0.69", "workspace-hack", ] diff --git a/modules/Cargo.lock b/modules/Cargo.lock index db252b3512..16a4588c02 100644 --- a/modules/Cargo.lock +++ b/modules/Cargo.lock @@ -512,18 +512,12 @@ version = "0.26.0" dependencies = [ "abstract-adapter", "abstract-adapter-utils", - "abstract-interface", "abstract-sdk", "abstract-std", "cosmwasm-schema", "cosmwasm-std", - "cw-address-like", "cw-asset", "cw-orch 0.27.0", - "cw-storage-plus", - "cw20", - "schemars", - "serde", "thiserror 1.0.69", "workspace-hack", ] From 5b2e03134ea2fc3bf00184acde480cc4d86f0121 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Wed, 8 Jan 2025 17:27:20 +0100 Subject: [PATCH 21/21] Removed unused deps --- interchain/Cargo.lock | 7 -- modules/Cargo.lock | 7 -- modules/contracts/adapters/oracle/Cargo.toml | 72 +++++++------------- 3 files changed, 25 insertions(+), 61 deletions(-) diff --git a/interchain/Cargo.lock b/interchain/Cargo.lock index 0cf9040b74..3f40e64f16 100644 --- a/interchain/Cargo.lock +++ b/interchain/Cargo.lock @@ -536,19 +536,12 @@ name = "abstract-oracle-adapter" version = "0.26.0" dependencies = [ "abstract-adapter", - "abstract-adapter-utils", "abstract-client", "abstract-oracle-standard", "abstract-pyth-adapter", "cosmwasm-schema", "cosmwasm-std", - "cw-asset", "cw-orch 0.27.0", - "cw-storage-plus", - "cw20", - "schemars", - "serde_json", - "thiserror 1.0.69", ] [[package]] diff --git a/modules/Cargo.lock b/modules/Cargo.lock index 16a4588c02..5cc27f291c 100644 --- a/modules/Cargo.lock +++ b/modules/Cargo.lock @@ -479,7 +479,6 @@ name = "abstract-oracle-adapter" version = "0.26.0" dependencies = [ "abstract-adapter", - "abstract-adapter-utils", "abstract-client", "abstract-interface", "abstract-oracle-adapter", @@ -490,19 +489,13 @@ dependencies = [ "clap 4.5.23", "cosmwasm-schema", "cosmwasm-std", - "cw-asset", "cw-orch 0.27.0", - "cw-orch-osmosis-test-tube", - "cw-storage-plus", "cw-utils", "cw20", "cw20-base", "dotenv", "env_logger 0.11.5", - "schemars", "semver", - "serde_json", - "thiserror 1.0.69", "tokio", ] diff --git a/modules/contracts/adapters/oracle/Cargo.toml b/modules/contracts/adapters/oracle/Cargo.toml index 1ee850fee1..ba363a7bb2 100644 --- a/modules/contracts/adapters/oracle/Cargo.toml +++ b/modules/contracts/adapters/oracle/Cargo.toml @@ -1,13 +1,13 @@ [package] description = "The oracle adapter is an Abstract adapter for querying oracle prices. It provides a common interface for all oracles" -name = "abstract-oracle-adapter" +name = "abstract-oracle-adapter" authors = { workspace = true } edition = { workspace = true } license = { workspace = true } version = { workspace = true } -exclude = ["contract.wasm", "hash.txt"] +exclude = ["contract.wasm", "hash.txt"] resolver = "2" @@ -18,19 +18,14 @@ crate-type = ["cdylib", "rlib"] name = "deploy" [[example]] -name = "schema" +name = "schema" required-features = ["schema"] [features] default = ["export"] -export = [] -schema = ["abstract-adapter/schema"] -testing = [ - "dep:abstract-client", - "dep:cw20", - "dep:serde_json", - "abstract-adapter/test-utils", -] +export = [] +schema = ["abstract-adapter/schema"] +testing = ["dep:abstract-client", "abstract-adapter/test-utils"] # Supported Oracles pyth = ["abstract-pyth-adapter/full_integration"] @@ -38,31 +33,18 @@ pyth = ["abstract-pyth-adapter/full_integration"] # Builds [package.metadata.optimizer] builds = [ - { name = "xion", features = [ - "pyth", - ] }, - { name = "neutron", features = [ - "pyth", - ] }, - { name = "osmosis", features = [ - "pyth", - ] }, + { name = "xion", features = ["pyth"] }, + { name = "neutron", features = ["pyth"] }, + { name = "osmosis", features = ["pyth"] }, ] [dependencies] abstract-adapter = { workspace = true } -cosmwasm-schema = { workspace = true } -cosmwasm-std = { workspace = true } -cw-asset = { workspace = true } -cw-orch = { workspace = true, features = ["daemon"] } -cw-orch-osmosis-test-tube = { workspace = true, optional = true } -cw-storage-plus = { workspace = true } -cw20 = { workspace = true, optional = true } -schemars = { workspace = true } -thiserror = { workspace = true } +cosmwasm-schema = { workspace = true } +cosmwasm-std = { workspace = true } +cw-orch = { workspace = true, features = ["daemon"] } # Local -abstract-adapter-utils = { workspace = true } abstract-oracle-standard = { workspace = true } # Pyth @@ -70,24 +52,20 @@ abstract-pyth-adapter = { path = "../../../../integrations/oracles/pyth" } # Testing # abstract-client = { workspace = true, optional = true } -serde_json = { version = "1.0", optional = true } [dev-dependencies] abstract-interface = { workspace = true, features = ["daemon"] } -anyhow = { workspace = true } -clap = { workspace = true } -dotenv = "0.15.0" -env_logger = "0.11.3" -semver = { workspace = true } -tokio = { workspace = true } - -bip32 = { version = "0.5.2" } -oracle = { path = ".", features = [ - "pyth", - "testing", -], package = "abstract-oracle-adapter" } - - -cw-utils = { workspace = true } -cw20 = { workspace = true } +anyhow = { workspace = true } +clap = { workspace = true } +dotenv = "0.15.0" +env_logger = "0.11.3" +semver = { workspace = true } +tokio = { workspace = true } + +bip32 = { version = "0.5.2" } +oracle = { path = ".", features = ["pyth", "testing"], package = "abstract-oracle-adapter" } + + +cw-utils = { workspace = true } +cw20 = { workspace = true } cw20-base = { workspace = true }