osmo_bindings/
query.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use crate::types::{Step, Swap, SwapAmount};
5use cosmwasm_std::{Coin, CustomQuery, Decimal, Uint128};
6
7#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
8#[serde(rename_all = "snake_case")]
9pub enum OsmosisQuery {
10    /// Given a sub-denom minted by a contract via `OsmosisMsg::MintTokens`,
11    /// returns the full denom as used by `BankMsg::Send`.
12    /// You may call `FullDenom { contract: env.contract.address, sub_denom }` to find the denom issued
13    /// by the current contract.
14    FullDenom { contract: String, sub_denom: String },
15    /// For a given pool ID, list all tokens traded on it with current liquidity (spot).
16    /// As well as the total number of LP shares and their denom
17    PoolState { id: u64 },
18    /// Return current spot price swapping In for Out on given pool ID.
19    /// Warning: this can easily be manipulated via sandwich attacks, do not use as price oracle.
20    /// We will add TWAP for more robust price feed.
21    SpotPrice { swap: Swap, with_swap_fee: bool },
22    /// Return current spot price swapping In for Out on given pool ID.
23    /// You can call `EstimateSwap { contract: env.contract.address, ... }` to set sender to the
24    /// current contract.
25    /// Warning: this can easily be manipulated via sandwich attacks, do not use as price oracle.
26    /// We will add TWAP for more robust price feed.
27    EstimateSwap {
28        sender: String,
29        first: Swap,
30        route: Vec<Step>,
31        amount: SwapAmount,
32    },
33}
34
35impl CustomQuery for OsmosisQuery {}
36
37impl OsmosisQuery {
38    /// Calculate spot price without swap fee
39    pub fn spot_price(pool_id: u64, denom_in: &str, denom_out: &str) -> Self {
40        OsmosisQuery::SpotPrice {
41            swap: Swap::new(pool_id, denom_in, denom_out),
42            with_swap_fee: false,
43        }
44    }
45
46    /// Basic helper to estimate price of a swap on one pool
47    pub fn estimate_swap(
48        contract: impl Into<String>,
49        pool_id: u64,
50        denom_in: impl Into<String>,
51        denom_out: impl Into<String>,
52        amount: SwapAmount,
53    ) -> Self {
54        OsmosisQuery::EstimateSwap {
55            sender: contract.into(),
56            first: Swap::new(pool_id, denom_in, denom_out),
57            amount,
58            route: vec![],
59        }
60    }
61}
62
63#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
64pub struct FullDenomResponse {
65    pub denom: String,
66}
67
68#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
69pub struct PoolStateResponse {
70    /// The various assets that be swapped. Including current liquidity.
71    pub assets: Vec<Coin>,
72    /// The number of lp shares and their amount
73    pub shares: Coin,
74}
75
76impl PoolStateResponse {
77    pub fn has_denom(&self, denom: &str) -> bool {
78        self.assets.iter().any(|c| c.denom == denom)
79    }
80
81    pub fn lp_denom(&self) -> &str {
82        &self.shares.denom
83    }
84
85    /// If I hold num_shares of the lp_denom, how many assets does that equate to?
86    pub fn shares_value(&self, num_shares: impl Into<Uint128>) -> Vec<Coin> {
87        let num_shares = num_shares.into();
88        self.assets
89            .iter()
90            .map(|c| Coin {
91                denom: c.denom.clone(),
92                amount: c.amount * num_shares / self.shares.amount,
93            })
94            .collect()
95    }
96}
97
98#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
99pub struct SpotPriceResponse {
100    /// How many output we would get for 1 input
101    pub price: Decimal,
102}
103
104#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
105pub struct SwapResponse {
106    // If you query with SwapAmount::Input, this is SwapAmount::Output
107    // If you query with SwapAmount::Output, this is SwapAmount::Input
108    pub amount: SwapAmount,
109}