From 68330441b20969f158d88ed03bfc27346d291a0e Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:42:27 -0700 Subject: [PATCH] docs: connect sdk cosmwasm (#779) --- docs/developers/connect-sdk.mdx | 98 ++++++++++++++++++ docs/developers/neutron-sdk.mdx | 170 -------------------------------- docs/mint.json | 2 +- 3 files changed, 99 insertions(+), 171 deletions(-) create mode 100644 docs/developers/connect-sdk.mdx delete mode 100644 docs/developers/neutron-sdk.mdx diff --git a/docs/developers/connect-sdk.mdx b/docs/developers/connect-sdk.mdx new file mode 100644 index 000000000..714e26d16 --- /dev/null +++ b/docs/developers/connect-sdk.mdx @@ -0,0 +1,98 @@ +--- +title: CosmWasm Connect SDK +description: Querying Connect prices using CosmWasm and Connect SDK +icon: atom-simple +--- + + +**Building with Connect? Join our [Discord](https://discord.gg/amAgf9Z39w)**! + + +The Connect SDK provides bindings for the `x/oracle` and `x/marketmap` modules. + +## Adding Connect SDK To Your Contract + +The version of the Connect SDK for your contract depends on the Connect protocol version of the chain. + +| Connect Protocol Version | Connect SDK Version | +|--------------------------|---------------------------------------| +| v1.x | v0.1.0 | +| v2.x | v0.2.0 | + + + How to find the Connect Protocol version + + The protocol version of Connect can be found on the chain by either: + + 1. Checking the chain's `go.mod` file. + 2. Checking the required version in the [quickstart](../validators/quickstart#run-connect-sidecar) + + +Add the following line to the `dependencies` section of your `Cargo.toml`: + +`connect-sdk = { git = "https://github.com/skip-mev/connect-sdk", tag = "CONNECT SDK VERSION HERE", package = "connect-sdk" }` + + + +## Safely Accessing Price Data + +The following checks should be made before utilizing a price from Connect in a contract: + +1. currency-pair exists within the `x/oracle` and `x/marketmap` modules. +2. currency-pair is `enabled` within the `x/marketmap`. +3. price `block_height` is not older than a few blocks. +4. price nonce is not 0. + + +### Code Example + +This code example is for `v0.1.0` of the Connect SDK. + +```rust contract.rs +use connect_sdk::bindings::query::ConnectQuery; +use connect_sdk::bindings::querier::ConnectQuerier; +use connect_sdk::bindings::marketmap::types::CurrencyPair; +use cosmwasm_std::{Deps, Env, StdResult, Int128, StdError}; + +fn do_something_with_price( + deps: Deps, + env: Env, + currency_pair: CurrencyPair +) -> StdResult { + let connect_querier = ConnectQuerier::new(&deps.querier); + let base = currency_pair.base.to_uppercase(); + let quote = currency_pair.quote.to_uppercase(); + + // Check if the market exists and is enabled + let market = connect_querier.get_marketmap_market(base.clone(), quote.clone())?; + if !market.market.ticker.enabled { + return Err(StdError::generic_err("market is not enabled")); + } + + // Check price validity + let price_response = connect_querier.get_oracle_price(base, quote)?; + if price_response.nonce == 0 { + return Err(StdError::generic_err("price has never been updated")); + } + + let max_price_age: u64 = 3; // adjust based on appetite for price freshness + let price_age = env.block.height - price_response.price.block_height.unwrap(); + if price_age > max_price_age { + return Err(StdError::generic_err("price is too old")); + } + + // We can now do something with the price + let valid_price = price_response.price.price; + + // Placeholder for actual price processing + Ok(valid_price) +} +``` + + + +## Full Example Contract + +Example Contract here: [example](https://github.com/skip-mev/connect-sdk/tree/trunk/contracts/x-oracle-passthrough). + + diff --git a/docs/developers/neutron-sdk.mdx b/docs/developers/neutron-sdk.mdx deleted file mode 100644 index b967b0c1d..000000000 --- a/docs/developers/neutron-sdk.mdx +++ /dev/null @@ -1,170 +0,0 @@ ---- -description: Querying Connect prices using CosmWasm and Neutron SDK -title: CosmWasm -icon: atom-simple ---- - - -**Building with Connect? Join our [Discord](https://discord.gg/amAgf9Z39w)**! - - -## Summary - -Connect prices are stored on-chain in `x/oracle`, enabling price data to be locally accessible via CosmWasm smart contracts. `x/marketmap` has configuration information that may also be helpful in your development. - -Here's how to get started: - -## How to access Connect prices safely - -There are a number of highly-recommended checks we suggest developers use before accessing a Connect price. These include: - -1. Check to make sure the currency-pair exists within the `x/oracle` and `x/marketmap` modules. -1. Check to make sure the currency-pair is `enabled` within the `x/marketmap` (otherwise, it won't update) -1. Check to make sure the `block_timestamp` of the last updated is **less than 20 seconds** from the most recent committed block timestamp. I.e. `current_block_timestamp - block_timestamp < 20s` -1. Check to make sure the price is not returning `nil` (i.e. has not been initialized) - -### Example - -The snippets below are not a complete implementation. Please check out the complete smart contract [example](https://github.com/kubiklabs/neutron-dev-contracts/tree/slinky_contracts/contracts/neutron_slinky) for a complete implementation. - -### Install dependencies and import the libraries - -Add the following libraries to your dependencies section: - -```toml -[dependencies] -cosmwasm-std = "1.3.1" - -# Other standard dependencies... - -# TODO: update to "neuton-sdk" version once released -neutron-sdk = { package = "neutron-sdk", git = "https://github.com/neutron-org/neutron-sdk", branch = "feat/sdk-50" } -``` - -Import the libraries: - -```rust -use neutron_sdk::bindings::marketmap::query::{ - MarketMapQuery, MarketMapResponse, MarketResponse, -}; -use neutron_sdk::bindings::oracle::types::CurrencyPair; -use neutron_sdk::bindings::{msg::NeutronMsg, query::NeutronQuery}; - -use neutron_sdk::bindings::oracle::query::{ - GetAllCurrencyPairsResponse, GetPriceResponse, GetPricesResponse, OracleQuery, -}; -``` - -### Getting all supported markets on Connect, and ensuring an individual market is included - -```rust -// create a CurrencyPair object -let currency_pair: CurrencyPair = CurrencyPair{ - base: base_symbol.clone(), quote: quote_currency.clone(), -}; - -// fetch all supported currency pairs in x/oracle module -let oracle_currency_pairs_query: OracleQuery = OracleQuery::GetAllCurrencyPairs{}; -let oracle_currency_pairs_response: GetAllCurrencyPairsResponse = deps.querier.query( - &oracle_currency_pairs_query.into(), -)?; -if oracle_currency_pairs_response.currency_pairs.contains(¤cy_pair) == false { - StdError::generic_err(format!( - "Market {base_symbol}, {quote_currency} not found in x/oracle module" - )); -} - -// fetch all supported currency pairs in x/marketmap module -let marketmap_currency_pairs_query: MarketMapQuery = MarketMapQuery::MarketMap{}; -let marketmap_currency_pairs_response: MarketMapResponse = deps.querier.query( - &marketmap_currency_pairs_query.into(), -)?; -if marketmap_currency_pairs_response.market_map.markets.contains_key(&base_symbol.clone()) == false { - StdError::generic_err(format!( - "Market {base_symbol}, {quote_currency} not found in x/marketmap module" - )); -} -``` - -### Checking if a market is `enabled` within `x/marketmap` - -```rust -// fetch market for currency_pair in x/marketmap module -let marketmap_market_query: MarketMapQuery = MarketMapQuery::Market{ - currency_pair: currency_pair.clone(), -}; -let marketmap_market_response: MarketResponse = deps.querier.query( - &marketmap_market_query.into(), -)?; - -// check if currency_pair is enabled -if marketmap_market_response.market.ticker.enabled == false { - StdError::generic_err(format!( - "Market {base_symbol}, {quote_currency} not enabled in x/marketmap module" - )); -} -``` - -### Checking if `block_timestamp` is recent enough - -```rust -// get current_block_height -let current_block_height: u64 = env.block.height; - -// fetch price for currency_pair from x/oracle module -let oracle_price_query: OracleQuery = OracleQuery::GetPrice{ - currency_pair: currency_pair.clone(), -}; -let oracle_price_response: GetPriceResponse = deps.querier.query( - &oracle_price_query.into(), -)?; - -// check if block_height is not too old -if (current_block_height - oracle_price_response.price.block_height) > max_blocks_old.u64() { - StdError::generic_err(format!( - "Market {base_symbol}, {quote_currency} price is older than {max_blocks_old} blocks" - )); -} -``` - -### Nil-checking a price response - -Connect may sometimes return a "nil" Price if it has not been written to. This means within the `GetPriceResponse`, the price will have `Nonce = 0` - -To check for a nil price, see if `Nonce == 0` in the `GetPrice` response. - -```rust -// fetch price for currency_pair from x/oracle module -let oracle_price_query: OracleQuery = OracleQuery::GetPrice{ - currency_pair: currency_pair.clone(), -}; -let oracle_price_response: GetPriceResponse = deps.querier.query( - &oracle_price_query.into(), -)?; - -if oracle_price_response.nonce == 0 { - StdError::generic_err(format!( - "Market {base_symbol}, {quote_currency} price is nil" - )); -} -``` - -### Fetching an individual price - -```rust -// fetch price for currency_pair from x/oracle module -let oracle_price_query: OracleQuery = OracleQuery::GetPrice{ - currency_pair: currency_pair.clone(), -}; -let oracle_price_response: GetPriceResponse = deps.querier.query( - &oracle_price_query.into(), -)?; - -let market_price: Int128 = oracle_price_response.price.price; -``` - -### Fetching a set of prices - -Fetching multiple prices at once requires using `OracleQuery::GetPrices { currency_pair_ids: Vec }` in place of `OracleQuery::GetPrice { currency_pair: CurrencyPair }`. Apply the same logic from the instructions above. - -For a complete example see the [full example](https://github.com/kubiklabs/neutron-dev-contracts/blob/slinky_contracts/contracts/neutron_slinky/src/contract.rs#L140-L242). diff --git a/docs/mint.json b/docs/mint.json index 3a3149e97..093f1d50c 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -68,7 +68,7 @@ "pages": [ "developers/integration", "developers/high-level", - "developers/neutron-sdk", + "developers/connect-sdk", "developers/providers", { "group": "Modules",