levana_perpswap_cosmos/
cosmwasm.rs

1use crate::prelude::*;
2use cosmwasm_std::{
3    Api, Binary, ContractResult, Empty, Event, QuerierWrapper, QueryRequest, StdError,
4    SystemResult, WasmQuery,
5};
6
7/// useful for placing an upper cap on query iterators
8/// as a safety measure to prevent exhausting resources on nodes that allow
9/// unbounded query gas
10pub const QUERY_MAX_LIMIT: u32 = 1000;
11
12/// Like [cosmwasm_std::Order] but serialized as a string
13/// and with a schema export
14#[cw_serde]
15#[derive(Eq, Copy)]
16#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
17pub enum OrderInMessage {
18    /// Ascending order
19    Ascending,
20    /// Descending order
21    Descending,
22}
23
24impl From<OrderInMessage> for cosmwasm_std::Order {
25    fn from(order: OrderInMessage) -> Self {
26        match order {
27            OrderInMessage::Ascending => Self::Ascending,
28            OrderInMessage::Descending => Self::Descending,
29        }
30    }
31}
32
33/// Extract an attribute for the given parameters from an Event
34fn extract_attribute<'a>(ty: &str, key: &str, events: &'a [Event]) -> Option<&'a str> {
35    events
36        .iter()
37        .find(|e| e.ty == ty)
38        .and_then(|ev| ev.attributes.iter().find(|a| a.key == key))
39        .map(|attr| attr.value.as_str())
40}
41
42// https://github.com/CosmWasm/wasmd/blob/main/EVENTS.md#standard-events-in-xwasm
43// but in practice it seems it's sometimes different
44/// Extract contract address from an instantiation event
45pub fn extract_instantiated_addr(api: &dyn Api, events: &[Event]) -> Result<Addr> {
46    for (ty, key) in [
47        (
48            "cosmwasm.wasm.v1.EventContractInstantiated",
49            "contract_address",
50        ),
51        ("instantiate", "_contract_address"),
52        ("instantiate", "_contract_addr"),
53        ("wasm", "contract_address"),
54        ("instantiate_contract", "contract_address"),
55    ] {
56        if let Some(addr) = extract_attribute(ty, key, events) {
57            let addr = addr
58                .strip_prefix('\"')
59                .and_then(|s| s.strip_suffix('\"'))
60                .unwrap_or(addr);
61            let addr = api.addr_validate(addr)?;
62            return Ok(addr);
63        }
64    }
65    Err(anyhow!("Couldn't find instantiated address"))
66}
67
68/// Make a smart query, but do not parse the binary results as JSON.
69///
70/// Useful for proxies where we need to pass along the binary results directly.
71pub fn smart_query_no_parse(
72    querier: &QuerierWrapper<Empty>,
73    contract_addr: impl Into<String>,
74    msg: &impl serde::Serialize,
75) -> anyhow::Result<Binary> {
76    let request: QueryRequest<Empty> = WasmQuery::Smart {
77        contract_addr: contract_addr.into(),
78        msg: cosmwasm_std::to_json_binary(msg)?,
79    }
80    .into();
81    let raw = cosmwasm_std::to_json_vec(&request).map_err(|serialize_err| {
82        StdError::generic_err(format!("Serializing QueryRequest: {}", serialize_err))
83    })?;
84    match querier.raw_query(&raw) {
85        SystemResult::Err(system_err) => Err(anyhow!("Querier system error: {}", system_err)),
86        SystemResult::Ok(ContractResult::Err(contract_err)) => {
87            Err(anyhow!("Querier contract error: {}", contract_err))
88        }
89        SystemResult::Ok(ContractResult::Ok(value)) => Ok(value),
90    }
91}