use serde::{de::DeserializeOwned, Serialize};
use std::ops::Deref;
use crate::addresses::{Addr, CanonicalAddr};
use crate::binary::Binary;
use crate::coins::Coin;
use crate::errors::{RecoverPubkeyError, StdError, StdResult, VerificationError};
#[cfg(feature = "iterator")]
use crate::iterator::{Order, Pair};
use crate::query::{
AllBalanceResponse, BalanceResponse, BankQuery, CustomQuery, QueryRequest, WasmQuery,
};
#[cfg(feature = "staking")]
use crate::query::{
AllDelegationsResponse, BondedDenomResponse, Delegation, DelegationResponse, FullDelegation,
StakingQuery, Validator, ValidatorsResponse,
};
use crate::results::{ContractResult, Empty, SystemResult};
use crate::serde::{from_binary, to_binary, to_vec};
pub trait Storage {
fn get(&self, key: &[u8]) -> Option<Vec<u8>>;
#[cfg(feature = "iterator")]
fn range<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
order: Order,
) -> Box<dyn Iterator<Item = Pair> + 'a>;
fn set(&mut self, key: &[u8], value: &[u8]);
fn remove(&mut self, key: &[u8]);
}
pub trait Api {
fn addr_validate(&self, human: &str) -> StdResult<Addr>;
fn addr_canonicalize(&self, human: &str) -> StdResult<CanonicalAddr>;
fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr>;
fn secp256k1_verify(
&self,
message_hash: &[u8],
signature: &[u8],
public_key: &[u8],
) -> Result<bool, VerificationError>;
fn secp256k1_recover_pubkey(
&self,
message_hash: &[u8],
signature: &[u8],
recovery_param: u8,
) -> Result<Vec<u8>, RecoverPubkeyError>;
fn ed25519_verify(
&self,
message: &[u8],
signature: &[u8],
public_key: &[u8],
) -> Result<bool, VerificationError>;
fn ed25519_batch_verify(
&self,
messages: &[&[u8]],
signatures: &[&[u8]],
public_keys: &[&[u8]],
) -> Result<bool, VerificationError>;
fn debug(&self, message: &str);
}
pub type QuerierResult = SystemResult<ContractResult<Binary>>;
pub trait Querier {
fn raw_query(&self, bin_request: &[u8]) -> QuerierResult;
}
#[derive(Copy, Clone)]
pub struct QuerierWrapper<'a>(&'a dyn Querier);
impl<'a> Deref for QuerierWrapper<'a> {
type Target = dyn Querier + 'a;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<'a> QuerierWrapper<'a> {
pub fn new(querier: &'a dyn Querier) -> Self {
QuerierWrapper(querier)
}
pub fn query<T: DeserializeOwned>(&self, request: &QueryRequest<Empty>) -> StdResult<T> {
self.custom_query(request)
}
pub fn custom_query<C: CustomQuery, U: DeserializeOwned>(
&self,
request: &QueryRequest<C>,
) -> StdResult<U> {
let raw = to_vec(request).map_err(|serialize_err| {
StdError::generic_err(format!("Serializing QueryRequest: {}", serialize_err))
})?;
match self.raw_query(&raw) {
SystemResult::Err(system_err) => Err(StdError::generic_err(format!(
"Querier system error: {}",
system_err
))),
SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(
format!("Querier contract error: {}", contract_err),
)),
SystemResult::Ok(ContractResult::Ok(value)) => from_binary(&value),
}
}
pub fn query_balance<U: Into<String>, V: Into<String>>(
&self,
address: U,
denom: V,
) -> StdResult<Coin> {
let request = BankQuery::Balance {
address: address.into(),
denom: denom.into(),
}
.into();
let res: BalanceResponse = self.query(&request)?;
Ok(res.amount)
}
pub fn query_all_balances<U: Into<String>>(&self, address: U) -> StdResult<Vec<Coin>> {
let request = BankQuery::AllBalances {
address: address.into(),
}
.into();
let res: AllBalanceResponse = self.query(&request)?;
Ok(res.amount)
}
pub fn query_wasm_smart<T: DeserializeOwned, U: Serialize, V: Into<String>>(
&self,
contract_addr: V,
msg: &U,
) -> StdResult<T> {
let request = WasmQuery::Smart {
contract_addr: contract_addr.into(),
msg: to_binary(msg)?,
}
.into();
self.query(&request)
}
pub fn query_wasm_raw<T: Into<String>, U: Into<Binary>>(
&self,
contract_addr: T,
key: U,
) -> StdResult<Option<Vec<u8>>> {
let request: QueryRequest<Empty> = WasmQuery::Raw {
contract_addr: contract_addr.into(),
key: key.into(),
}
.into();
let raw = to_vec(&request).map_err(|serialize_err| {
StdError::generic_err(format!("Serializing QueryRequest: {}", serialize_err))
})?;
match self.raw_query(&raw) {
SystemResult::Err(system_err) => Err(StdError::generic_err(format!(
"Querier system error: {}",
system_err
))),
SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(
format!("Querier contract error: {}", contract_err),
)),
SystemResult::Ok(ContractResult::Ok(value)) => {
if value.is_empty() {
Ok(None)
} else {
Ok(Some(value.into()))
}
}
}
}
#[cfg(feature = "staking")]
pub fn query_validators(&self) -> StdResult<Vec<Validator>> {
let request = StakingQuery::Validators {}.into();
let res: ValidatorsResponse = self.query(&request)?;
Ok(res.validators)
}
#[cfg(feature = "staking")]
pub fn query_bonded_denom(&self) -> StdResult<String> {
let request = StakingQuery::BondedDenom {}.into();
let res: BondedDenomResponse = self.query(&request)?;
Ok(res.denom)
}
#[cfg(feature = "staking")]
pub fn query_all_delegations<U: Into<String>>(
&self,
delegator: U,
) -> StdResult<Vec<Delegation>> {
let request = StakingQuery::AllDelegations {
delegator: delegator.into(),
}
.into();
let res: AllDelegationsResponse = self.query(&request)?;
Ok(res.delegations)
}
#[cfg(feature = "staking")]
pub fn query_delegation<U: Into<String>, V: Into<String>>(
&self,
delegator: U,
validator: V,
) -> StdResult<Option<FullDelegation>> {
let request = StakingQuery::Delegation {
delegator: delegator.into(),
validator: validator.into(),
}
.into();
let res: DelegationResponse = self.query(&request)?;
Ok(res.delegation)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mock::MockQuerier;
use crate::{coins, from_slice, Uint128};
fn demo_helper(_querier: &dyn Querier) -> u64 {
2
}
#[test]
fn use_querier_wrapper_as_querier() {
let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
let wrapper = QuerierWrapper::new(&querier);
let res = demo_helper(&*wrapper);
assert_eq!(2, res);
let res = demo_helper(wrapper.deref());
assert_eq!(2, res);
}
#[test]
fn auto_deref_raw_query() {
let acct = String::from("foobar");
let querier: MockQuerier<Empty> = MockQuerier::new(&[(&acct, &coins(5, "BTC"))]);
let wrapper = QuerierWrapper::new(&querier);
let query = QueryRequest::<Empty>::Bank(BankQuery::Balance {
address: acct,
denom: "BTC".to_string(),
});
let raw = wrapper
.raw_query(&to_vec(&query).unwrap())
.unwrap()
.unwrap();
let balance: BalanceResponse = from_slice(&raw).unwrap();
assert_eq!(balance.amount.amount, Uint128(5));
}
}