diff --git a/contracts/tgrade-trusted-circle/src/contract.rs b/contracts/tgrade-trusted-circle/src/contract.rs index 9ea371db..609e807a 100644 --- a/contracts/tgrade-trusted-circle/src/contract.rs +++ b/contracts/tgrade-trusted-circle/src/contract.rs @@ -1,8 +1,9 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - coin, to_binary, Addr, BankMsg, Binary, BlockInfo, Deps, DepsMut, Env, Event, MessageInfo, - Order, QuerierWrapper, StdError, StdResult, Storage, Uint128, + coin, to_binary, to_vec, Addr, BankMsg, Binary, BlockInfo, ContractResult, Deps, DepsMut, + Empty, Env, Event, MessageInfo, Order, QuerierWrapper, QueryRequest, StdError, StdResult, + Storage, SystemError, SystemResult, Uint128, WasmQuery, }; use cw0::{maybe_addr, Expiration}; use cw2::set_contract_version; @@ -1197,24 +1198,26 @@ pub fn remove_contract_addr( Ok(vec![ev]) } -// FIXME: I just checked wasmd and multitest. They do not return this error properly. -// We can either: -// 1. Update wasmd and multitest behavior -// 2. Upgrade to CosmWasm 1.0.0-beta and use WasmQuery::ContractInfo{} -// 3. QueryRaw for some known key we expect to be present in all contracts. Return true only if we get data from QueryRaw -// The best I can think of is from cw2: -// https://github.com/CosmWasm/cw-plus/blob/f78cb1535db2cd8c606de01c91d60814c03cff7e/packages/cw2/src/lib.rs#L7 -// -// wasmd query entry points: https://github.com/CosmWasm/wasmd/blob/master/x/wasm/keeper/query_plugins.go#L466-L477 -// wasmd error returned on QuerySmart: https://github.com/CosmWasm/wasmd/blob/6a471a4a16730e371863067b27858f60a3996c91/x/wasm/keeper/keeper.go#L627 -// no error returned on QueryRaw: https://github.com/CosmWasm/wasmd/blob/6a471a4a16730e371863067b27858f60a3996c91/x/wasm/keeper/keeper.go#L612-L620 pub fn is_contract(querier: &QuerierWrapper, addr: &Addr) -> StdResult { - // see cw2.CONTRACT - match querier.query_wasm_raw(addr, b"contract_info") { - Ok(Some(data)) if !data.is_empty() => Ok(true), - Ok(_) => Ok(false), - Err(StdError::GenericErr { msg, .. }) if msg.contains("No such contract") => Ok(false), - Err(err) => Err(err), + let raw = QueryRequest::::Wasm(WasmQuery::ContractInfo { + contract_addr: addr.to_string(), + }); + match querier.raw_query(&to_vec(&raw)?) { + SystemResult::Err(SystemError::NoSuchContract { .. }) => Ok(false), + SystemResult::Err(system_err) => Err(StdError::generic_err(format!( + "Querier system error: {}", + system_err + ))), + SystemResult::Ok(ContractResult::Err(contract_err)) + if contract_err.contains("not found") => + { + Ok(false) + } + SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(format!( + "Querier contract error: {}", + contract_err + ))), + SystemResult::Ok(ContractResult::Ok(_)) => Ok(true), } } diff --git a/contracts/tgrade-trusted-circle/src/tests/unit_tests.rs b/contracts/tgrade-trusted-circle/src/tests/unit_tests.rs index e79e7ef4..7c11b304 100644 --- a/contracts/tgrade-trusted-circle/src/tests/unit_tests.rs +++ b/contracts/tgrade-trusted-circle/src/tests/unit_tests.rs @@ -1,11 +1,12 @@ #![cfg(test)] use super::*; +use serde::{Deserialize, Serialize}; use std::marker::PhantomData; use cosmwasm_std::testing::{MockApi, MockStorage}; use cosmwasm_std::{ - Addr, Binary, ContractResult, Deps, Empty, QuerierResult, QueryRequest, StdError, SubMsg, - SystemError, SystemResult, WasmQuery, + to_binary, Addr, Binary, ContractResult, Deps, Empty, QuerierResult, QueryRequest, StdError, + SubMsg, SystemError, SystemResult, WasmQuery, }; use cw_storage_plus::Item; @@ -22,6 +23,20 @@ struct TokenQuerier { storage: MockStorage, } +// TODO: we should import this from cosmwasm-std, but cannot due to non_exhaustive so copy here +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct ContractInfoResponse { + pub code_id: u64, + /// address that instantiated this contract + pub creator: String, + /// admin who can run migrations (if any) + pub admin: Option, + /// if set, the contract is pinned to the cache, and thus uses less gas when called + pub pinned: bool, + /// set if this contract has bound an IBC port + pub ibc_port: Option, +} + impl TokenQuerier { pub fn new(contract: &Addr, token_version: &str) -> Self { let mut storage = MockStorage::new(); @@ -45,6 +60,9 @@ impl TokenQuerier { kind: "WasmQuery::Smart".to_string(), }) } + QueryRequest::Wasm(WasmQuery::ContractInfo { contract_addr }) => { + self.query_contract_info(contract_addr) + } _ => SystemResult::Err(SystemError::UnsupportedRequest { kind: "not wasm".to_string(), }), @@ -62,6 +80,34 @@ impl TokenQuerier { SystemResult::Ok(ContractResult::Ok(bin.into())) } } + + fn query_contract_info(&self, contract_addr: String) -> QuerierResult { + if contract_addr != self.contract { + SystemResult::Err(SystemError::NoSuchContract { + addr: contract_addr, + }) + } else { + // FIXME: Implement mock load_contract and use it here + /* let contract = self.storage.load_contract(&addr)?; + let res = ContractInfoResponse { + code_id: contract.code_id as u64, + creator: contract.creator.to_string(), + admin: contract.admin.map(|x| x.to_string()), + pinned: false, + ibc_port: None, + }; + */ + let res = ContractInfoResponse { + code_id: 1, + creator: "dummy_creator".into(), + admin: None, + pinned: false, + ibc_port: None, + }; + let bin = to_binary(&res).unwrap(); + SystemResult::Ok(ContractResult::Ok(bin)) + } + } } impl Querier for TokenQuerier {