1use std::fmt;
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use cosmwasm_std::{Addr, Api, StdResult, Uint128};
7
8use crate::math::decimal::Decimal;
9
10#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
11#[serde(rename_all = "snake_case")]
12pub enum PriceSource<A> {
13 Fixed { price: Decimal },
15 Native { denom: String },
17 AstroportSpot {
21 pair_address: A,
23 },
24 AstroportTwap {
28 pair_address: A,
30 window_size: u64,
35 tolerance: u64,
43 },
44 AstroportLiquidityToken {
50 pair_address: A,
52 },
53}
54
55impl<A> fmt::Display for PriceSource<A> {
56 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57 let label = match self {
58 PriceSource::Fixed { .. } => "fixed",
59 PriceSource::Native { .. } => "native",
60 PriceSource::AstroportSpot { .. } => "astroport_spot",
61 PriceSource::AstroportTwap { .. } => "astroport_twap",
62 PriceSource::AstroportLiquidityToken { .. } => "astroport_liquidity_token",
63 };
64 write!(f, "{}", label)
65 }
66}
67
68pub type PriceSourceUnchecked = PriceSource<String>;
69pub type PriceSourceChecked = PriceSource<Addr>;
70
71impl PriceSourceUnchecked {
72 pub fn to_checked(&self, api: &dyn Api) -> StdResult<PriceSourceChecked> {
73 Ok(match self {
74 PriceSourceUnchecked::Fixed { price } => PriceSourceChecked::Fixed { price: *price },
75 PriceSourceUnchecked::Native { denom } => PriceSourceChecked::Native {
76 denom: denom.clone(),
77 },
78 PriceSourceUnchecked::AstroportSpot { pair_address } => {
79 PriceSourceChecked::AstroportSpot {
80 pair_address: api.addr_validate(pair_address)?,
81 }
82 }
83 PriceSourceUnchecked::AstroportTwap {
84 pair_address,
85 window_size,
86 tolerance,
87 } => PriceSourceChecked::AstroportTwap {
88 pair_address: api.addr_validate(pair_address)?,
89 window_size: *window_size,
90 tolerance: *tolerance,
91 },
92 PriceSourceUnchecked::AstroportLiquidityToken { pair_address } => {
93 PriceSourceChecked::AstroportLiquidityToken {
94 pair_address: api.addr_validate(pair_address)?,
95 }
96 }
97 })
98 }
99}
100
101#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
103pub struct Config {
104 pub owner: Addr,
105}
106
107#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
108pub struct AstroportTwapSnapshot {
109 pub timestamp: u64,
111 pub price_cumulative: Uint128,
113}
114
115pub mod msg {
116 use schemars::JsonSchema;
117 use serde::{Deserialize, Serialize};
118
119 use super::PriceSourceUnchecked;
120 use crate::asset::Asset;
121
122 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
123 pub struct InstantiateMsg {
124 pub owner: String,
125 }
126
127 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
128 #[serde(rename_all = "snake_case")]
129 pub enum ExecuteMsg {
130 UpdateConfig { owner: Option<String> },
132 SetAsset {
134 asset: Asset,
135 price_source: PriceSourceUnchecked,
136 },
137 RecordTwapSnapshots { assets: Vec<Asset> },
139 }
140
141 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
142 #[serde(rename_all = "snake_case")]
143 pub enum QueryMsg {
144 Config {},
146 AssetPriceSource { asset: Asset },
148 AssetPrice { asset: Asset },
150 AssetPriceByReference { asset_reference: Vec<u8> },
154 }
155}
156
157pub mod helpers {
158 use cosmwasm_std::{to_binary, Addr, QuerierWrapper, QueryRequest, StdResult, WasmQuery};
159
160 use crate::asset::AssetType;
161 use crate::math::decimal::Decimal;
162
163 use super::msg::QueryMsg;
164
165 pub fn query_price(
166 querier: QuerierWrapper,
167 oracle_address: Addr,
168 asset_label: &str,
169 asset_reference: Vec<u8>,
170 asset_type: AssetType,
171 ) -> StdResult<Decimal> {
172 if asset_type == AssetType::Native && asset_label == "uusd" {
174 Ok(Decimal::one())
175 } else {
176 querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
177 contract_addr: oracle_address.into(),
178 msg: to_binary(&QueryMsg::AssetPriceByReference { asset_reference })?,
179 }))
180 }
181 }
182}