Skip to content

Commit 3c009f4

Browse files
authored
Pyth v1 (#193)
* Pyth (#183) * Pyth integration. * Add mocks. * Add validation. * Tests. * Add update_config. * Update schema. * Apply review comments. * Update clippy. * MP-2475. Pyth phase 1 aligment. * Implementation for LSD v1 (#190) * Add LSD price source. * Split PriceSource to Unchecked and Checked. * LSD fmt. * Query LSD price. * Fix tests. * Add tests for LSD. * Update schema. * Apply comments from review. * Extract pyth addr to Pyth price source config. * Update decimals (#194) * Add decimals for Pyth prices. * Update schema. * Fix fmt. * Fix missing cw dep. * Add base_denom_decimals for price normalization in Pyth. * Add config arg. Change query_price signature. * Move fmt test cases. * Update comment. * Fix clippy. * Update comment. * Use wasm from optimizer for integration tests. * Fix pipeline. * Improve pyth base dec (#202) * Use price source for usd -> base_denom convertion. * Fix test and update comments. * Fix fmt. * Bump deps (#204) * Bump deps. Fix build. * Migrate Spot / Pool queries to poolmanager. * Use GammQueries for Spot. New PoolManager query is not yet whitelisted. * Bump contract ver and rust-optimizer. * Use old Pool query. * Set version to 1.1.0. * Migrate owner state. (#205)
1 parent fb45dd3 commit 3c009f4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2491
-461
lines changed

Cargo.lock

Lines changed: 158 additions & 93 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ members = [
1414
]
1515

1616
[workspace.package]
17-
version = "1.0.1"
17+
version = "1.1.0"
1818
authors = [
1919
"Larry Engineer <[email protected]>",
2020
"Piotr Babel <[email protected]>",
@@ -30,21 +30,22 @@ documentation = "https://docs.marsprotocol.io/"
3030
keywords = ["mars", "cosmos", "cosmwasm"]
3131

3232
[workspace.dependencies]
33-
anyhow = "1.0.68"
33+
anyhow = "1.0.71"
3434
bech32 = "0.9.1"
35-
cosmwasm-schema = "1.1.9"
36-
cosmwasm-std = "1.1.9"
37-
cw2 = { git = "https://github.com/mars-protocol/cw-plus", rev = "4014255" }
38-
cw-multi-test = "0.16.1"
35+
cosmwasm-schema = "1.2.6"
36+
cosmwasm-std = "1.2.6"
37+
cw2 = { git = "https://github.com/CosmWasm/cw-plus", rev = "de1fb0b" }
38+
cw-multi-test = "0.16.5"
3939
cw-storage-plus = "1.0.1"
4040
cw-utils = "1.0.1"
4141
mars-owner = { version = "1.2.0", features = ["emergency-owner"] }
42-
osmosis-std = "0.14.0"
42+
osmosis-std = "0.15.3"
4343
osmosis-test-tube = "15.1.0"
4444
prost = { version = "0.11.5", default-features = false, features = ["prost-derive"] }
45-
schemars = "0.8.11"
46-
serde = { version = "1.0.152", default-features = false, features = ["derive"] }
47-
thiserror = "1.0.38"
45+
pyth-sdk-cw = "1.2.0"
46+
schemars = "0.8.12"
47+
serde = { version = "1.0.163", default-features = false, features = ["derive"] }
48+
thiserror = "1.0.40"
4849

4950
# packages
5051
mars-health = { version = "1.0.0", path = "./packages/health" }

Makefile.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ args = ["build", "--release", "--target", "wasm32-unknown-unknown", "--locked"]
1818
[tasks.rust-optimizer]
1919
script = """
2020
if [[ $(arch) == "arm64" ]]; then
21-
image="cosmwasm/workspace-optimizer-arm64:0.12.11"
21+
image="cosmwasm/workspace-optimizer-arm64:0.12.13"
2222
else
23-
image="cosmwasm/workspace-optimizer:0.12.11"
23+
image="cosmwasm/workspace-optimizer:0.12.13"
2424
fi
2525
docker run --rm -v "$(pwd)":/code \
2626
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \

contracts/oracle/base/src/contract.rs

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ use mars_red_bank_types::oracle::{
1212
};
1313
use mars_utils::helpers::validate_native_denom;
1414

15-
use crate::{error::ContractResult, PriceSource};
15+
use crate::{error::ContractResult, PriceSourceChecked, PriceSourceUnchecked};
1616

1717
const DEFAULT_LIMIT: u32 = 10;
1818
const MAX_LIMIT: u32 = 30;
1919

20-
pub struct OracleBase<'a, P, C>
20+
pub struct OracleBase<'a, P, PU, C>
2121
where
22-
P: PriceSource<C>,
22+
P: PriceSourceChecked<C>,
23+
PU: PriceSourceUnchecked<P, C>,
2324
C: CustomQuery,
2425
{
2526
/// Contract's owner
@@ -28,28 +29,33 @@ where
2829
pub config: Item<'a, Config>,
2930
/// The price source of each coin denom
3031
pub price_sources: Map<'a, &'a str, P>,
32+
/// Phantom data holds the unchecked price source type
33+
pub unchecked_price_source: PhantomData<PU>,
3134
/// Phantom data holds the custom query type
3235
pub custom_query: PhantomData<C>,
3336
}
3437

35-
impl<'a, P, C> Default for OracleBase<'a, P, C>
38+
impl<'a, P, PU, C> Default for OracleBase<'a, P, PU, C>
3639
where
37-
P: PriceSource<C>,
40+
P: PriceSourceChecked<C>,
41+
PU: PriceSourceUnchecked<P, C>,
3842
C: CustomQuery,
3943
{
4044
fn default() -> Self {
4145
Self {
4246
owner: Owner::new("owner"),
4347
config: Item::new("config"),
4448
price_sources: Map::new("price_sources"),
49+
unchecked_price_source: PhantomData,
4550
custom_query: PhantomData,
4651
}
4752
}
4853
}
4954

50-
impl<'a, P, C> OracleBase<'a, P, C>
55+
impl<'a, P, PU, C> OracleBase<'a, P, PU, C>
5156
where
52-
P: PriceSource<C>,
57+
P: PriceSourceChecked<C>,
58+
PU: PriceSourceUnchecked<P, C>,
5359
C: CustomQuery,
5460
{
5561
pub fn instantiate(&self, deps: DepsMut<C>, msg: InstantiateMsg) -> ContractResult<Response> {
@@ -77,7 +83,7 @@ where
7783
&self,
7884
deps: DepsMut<C>,
7985
info: MessageInfo,
80-
msg: ExecuteMsg<P>,
86+
msg: ExecuteMsg<PU>,
8187
) -> ContractResult<Response> {
8288
match msg {
8389
ExecuteMsg::UpdateOwner(update) => self.update_owner(deps, info, update),
@@ -88,6 +94,9 @@ where
8894
ExecuteMsg::RemovePriceSource {
8995
denom,
9096
} => self.remove_price_source(deps, info.sender, denom),
97+
ExecuteMsg::UpdateConfig {
98+
base_denom,
99+
} => self.update_config(deps, info.sender, base_denom),
91100
}
92101
}
93102

@@ -126,14 +135,14 @@ where
126135
deps: DepsMut<C>,
127136
sender_addr: Addr,
128137
denom: String,
129-
price_source: P,
138+
price_source: PU,
130139
) -> ContractResult<Response> {
131140
self.owner.assert_owner(deps.storage, &sender_addr)?;
132141

133142
validate_native_denom(&denom)?;
134143

135144
let cfg = self.config.load(deps.storage)?;
136-
price_source.validate(&deps.querier, &denom, &cfg.base_denom)?;
145+
let price_source = price_source.validate(deps.as_ref(), &denom, &cfg.base_denom)?;
137146
self.price_sources.save(deps.storage, &denom, &price_source)?;
138147

139148
Ok(Response::new()
@@ -157,6 +166,31 @@ where
157166
.add_attribute("denom", denom))
158167
}
159168

169+
fn update_config(
170+
&self,
171+
deps: DepsMut<C>,
172+
sender_addr: Addr,
173+
base_denom: Option<String>,
174+
) -> ContractResult<Response> {
175+
self.owner.assert_owner(deps.storage, &sender_addr)?;
176+
177+
if let Some(bd) = &base_denom {
178+
validate_native_denom(bd)?;
179+
};
180+
181+
let mut config = self.config.load(deps.storage)?;
182+
let prev_base_denom = config.base_denom.clone();
183+
config.base_denom = base_denom.unwrap_or(config.base_denom);
184+
self.config.save(deps.storage, &config)?;
185+
186+
let response = Response::new()
187+
.add_attribute("action", "update_config")
188+
.add_attribute("prev_base_denom", prev_base_denom)
189+
.add_attribute("base_denom", config.base_denom);
190+
191+
Ok(response)
192+
}
193+
160194
fn query_config(&self, deps: Deps<C>) -> StdResult<ConfigResponse> {
161195
let owner_state = self.owner.query(deps.storage)?;
162196
let cfg = self.config.load(deps.storage)?;
@@ -204,13 +238,7 @@ where
204238
let cfg = self.config.load(deps.storage)?;
205239
let price_source = self.price_sources.load(deps.storage, &denom)?;
206240
Ok(PriceResponse {
207-
price: price_source.query_price(
208-
&deps,
209-
&env,
210-
&denom,
211-
&cfg.base_denom,
212-
&self.price_sources,
213-
)?,
241+
price: price_source.query_price(&deps, &env, &denom, &cfg, &self.price_sources)?,
214242
denom,
215243
})
216244
}
@@ -233,7 +261,7 @@ where
233261
.map(|item| {
234262
let (k, v) = item?;
235263
Ok(PriceResponse {
236-
price: v.query_price(&deps, &env, &k, &cfg.base_denom, &self.price_sources)?,
264+
price: v.query_price(&deps, &env, &k, &cfg, &self.price_sources)?,
237265
denom: k,
238266
})
239267
})

contracts/oracle/base/src/error.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use cosmwasm_std::{ConversionOverflowError, OverflowError, StdError};
1+
use cosmwasm_std::{
2+
CheckedFromRatioError, CheckedMultiplyRatioError, ConversionOverflowError,
3+
DecimalRangeExceeded, OverflowError, StdError,
4+
};
25
use mars_owner::OwnerError;
36
use mars_red_bank_types::error::MarsError;
47
use mars_utils::error::ValidationError;
@@ -27,6 +30,15 @@ pub enum ContractError {
2730
#[error("{0}")]
2831
Overflow(#[from] OverflowError),
2932

33+
#[error("{0}")]
34+
CheckedMultiplyRatio(#[from] CheckedMultiplyRatioError),
35+
36+
#[error("{0}")]
37+
CheckedFromRatio(#[from] CheckedFromRatioError),
38+
39+
#[error("{0}")]
40+
DecimalRangeExceeded(#[from] DecimalRangeExceeded),
41+
3042
#[error("Invalid price source: {reason}")]
3143
InvalidPriceSource {
3244
reason: String,
Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
11
use std::fmt::{Debug, Display};
22

3-
use cosmwasm_std::{CustomQuery, Decimal, Deps, Env, QuerierWrapper};
3+
use cosmwasm_std::{CustomQuery, Decimal, Deps, Env};
44
use cw_storage_plus::Map;
5+
use mars_red_bank_types::oracle::Config;
56
use schemars::JsonSchema;
67
use serde::{de::DeserializeOwned, Serialize};
78

89
use crate::ContractResult;
910

10-
pub trait PriceSource<C>:
11-
Serialize + DeserializeOwned + Clone + Debug + Display + PartialEq + JsonSchema
11+
pub trait PriceSourceUnchecked<P, C>:
12+
Serialize + DeserializeOwned + Clone + Debug + PartialEq + JsonSchema
1213
where
14+
P: PriceSourceChecked<C>,
1315
C: CustomQuery,
1416
{
1517
/// Validate whether the price source is valid for a given denom
16-
fn validate(
17-
&self,
18-
querier: &QuerierWrapper<C>,
19-
denom: &str,
20-
base_denom: &str,
21-
) -> ContractResult<()>;
18+
fn validate(self, deps: Deps<C>, denom: &str, base_denom: &str) -> ContractResult<P>;
19+
}
2220

21+
pub trait PriceSourceChecked<C>:
22+
Serialize + DeserializeOwned + Clone + Debug + Display + PartialEq + JsonSchema
23+
where
24+
C: CustomQuery,
25+
{
2326
/// Query the price of an asset based on the given price source
2427
///
2528
/// Notable arguments:
2629
///
2730
/// - `denom`: The coin whose price is to be queried.
2831
///
29-
/// - `base_denom`: The coin in which the price is to be denominated in.
32+
/// - `config.base_denom`: The coin in which the price is to be denominated in.
3033
/// For example, if `denom` is uatom and `base_denom` is uosmo, the
3134
/// function should return how many uosmo is per one uatom.
3235
///
@@ -39,7 +42,7 @@ where
3942
deps: &Deps<C>,
4043
env: &Env,
4144
denom: &str,
42-
base_denom: &str,
45+
config: &Config,
4346
price_sources: &Map<&str, Self>,
4447
) -> ContractResult<Decimal>;
4548
}

contracts/oracle/osmosis/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ doctest = false
1919
backtraces = ["cosmwasm-std/backtraces"]
2020

2121
[dependencies]
22+
cosmwasm-schema = { workspace = true }
2223
cosmwasm-std = { workspace = true }
2324
cw2 = { workspace = true }
2425
cw-storage-plus = { workspace = true }
26+
mars-owner = { workspace = true }
2527
mars-oracle-base = { workspace = true }
2628
mars-osmosis = { workspace = true }
2729
mars-red-bank-types = { workspace = true }
2830
osmosis-std = { workspace = true }
31+
pyth-sdk-cw = { workspace = true }
2932
schemars = { workspace = true }
3033
serde = { workspace = true }
3134
thiserror = { workspace = true }
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use cosmwasm_schema::write_api;
2-
use mars_oracle_osmosis::OsmosisPriceSource;
2+
use mars_oracle_osmosis::OsmosisPriceSourceUnchecked;
33
use mars_red_bank_types::oracle::{ExecuteMsg, InstantiateMsg, QueryMsg};
44

55
fn main() {
66
write_api! {
77
instantiate: InstantiateMsg,
8-
execute: ExecuteMsg<OsmosisPriceSource>,
8+
execute: ExecuteMsg<OsmosisPriceSourceUnchecked>,
99
query: QueryMsg,
1010
}
1111
}

contracts/oracle/osmosis/src/contract.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use cosmwasm_std::Empty;
22
use mars_oracle_base::OracleBase;
33

4-
use crate::OsmosisPriceSource;
4+
use crate::price_source::{OsmosisPriceSourceChecked, OsmosisPriceSourceUnchecked};
55

66
/// The Osmosis oracle contract inherits logics from the base oracle contract, with the Osmosis query
77
/// and price source plugins
8-
pub type OsmosisOracle<'a> = OracleBase<'a, OsmosisPriceSource, Empty>;
8+
pub type OsmosisOracle<'a> =
9+
OracleBase<'a, OsmosisPriceSourceChecked, OsmosisPriceSourceUnchecked, Empty>;
910

1011
pub const CONTRACT_NAME: &str = "crates.io:mars-oracle-osmosis";
1112
pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -35,7 +36,7 @@ pub mod entry {
3536
deps: DepsMut,
3637
_env: Env,
3738
info: MessageInfo,
38-
msg: ExecuteMsg<OsmosisPriceSource>,
39+
msg: ExecuteMsg<OsmosisPriceSourceUnchecked>,
3940
) -> ContractResult<Response> {
4041
OsmosisOracle::default().execute(deps, info, msg)
4142
}
@@ -47,6 +48,6 @@ pub mod entry {
4748

4849
#[entry_point]
4950
pub fn migrate(deps: DepsMut, _env: Env, _msg: Empty) -> ContractResult<Response> {
50-
migrations::v1_0_0::migrate(deps)
51+
migrations::v1_0_1::migrate(deps)
5152
}
5253
}

contracts/oracle/osmosis/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,9 @@ mod helpers;
33
mod migrations;
44
pub mod msg;
55
mod price_source;
6+
pub mod stride;
67

7-
pub use price_source::{Downtime, DowntimeDetector, OsmosisPriceSource};
8+
pub use price_source::{
9+
scale_pyth_price, Downtime, DowntimeDetector, GeometricTwap, OsmosisPriceSourceChecked,
10+
OsmosisPriceSourceUnchecked, RedemptionRate,
11+
};

0 commit comments

Comments
 (0)