use cosmwasm_bignumber::Decimal256;
use cosmwasm_std::testing::{MockApi, MockQuerier, MockStorage, MOCK_CONTRACT_ADDR};
use cosmwasm_std::{
from_binary, from_slice, to_binary, Coin, ContractResult, Decimal, OwnedDeps, Querier,
QuerierResult, QueryRequest, SystemError, SystemResult, Uint128, WasmQuery,
};
use std::collections::HashMap;
use crate::oracle::{PriceResponse, QueryMsg as OracleQueryMsg};
use terra_cosmwasm::{TaxCapResponse, TaxRateResponse, TerraQuery, TerraQueryWrapper, TerraRoute};
pub fn mock_dependencies(
contract_balance: &[Coin],
) -> OwnedDeps<MockStorage, MockApi, WasmMockQuerier> {
let custom_querier: WasmMockQuerier =
WasmMockQuerier::new(MockQuerier::new(&[(MOCK_CONTRACT_ADDR, contract_balance)]));
OwnedDeps {
storage: MockStorage::default(),
api: MockApi::default(),
querier: custom_querier,
}
}
pub struct WasmMockQuerier {
base: MockQuerier<TerraQueryWrapper>,
tax_querier: TaxQuerier,
oracle_price_querier: OraclePriceQuerier,
}
#[derive(Clone, Default)]
pub struct TaxQuerier {
rate: Decimal,
caps: HashMap<String, Uint128>,
}
impl TaxQuerier {
pub fn new(rate: Decimal, caps: &[(&String, &Uint128)]) -> Self {
TaxQuerier {
rate,
caps: caps_to_map(caps),
}
}
}
pub(crate) fn caps_to_map(caps: &[(&String, &Uint128)]) -> HashMap<String, Uint128> {
let mut owner_map: HashMap<String, Uint128> = HashMap::new();
for (denom, cap) in caps.iter() {
owner_map.insert(denom.to_string(), **cap);
}
owner_map
}
#[derive(Clone, Default)]
pub struct OraclePriceQuerier {
oracle_price: HashMap<(String, String), (Decimal256, u64, u64)>,
}
#[allow(clippy::type_complexity)]
impl OraclePriceQuerier {
pub fn new(oracle_price: &[(&(String, String), &(Decimal256, u64, u64))]) -> Self {
OraclePriceQuerier {
oracle_price: oracle_price_to_map(oracle_price),
}
}
}
#[allow(clippy::type_complexity)]
pub(crate) fn oracle_price_to_map(
oracle_price: &[(&(String, String), &(Decimal256, u64, u64))],
) -> HashMap<(String, String), (Decimal256, u64, u64)> {
let mut oracle_price_map: HashMap<(String, String), (Decimal256, u64, u64)> = HashMap::new();
for (base_quote, oracle_price) in oracle_price.iter() {
oracle_price_map.insert((*base_quote).clone(), **oracle_price);
}
oracle_price_map
}
impl Querier for WasmMockQuerier {
fn raw_query(&self, bin_request: &[u8]) -> QuerierResult {
let request: QueryRequest<TerraQueryWrapper> = match from_slice(bin_request) {
Ok(v) => v,
Err(e) => {
return SystemResult::Err(SystemError::InvalidRequest {
error: format!("Parsing query request: {}", e),
request: bin_request.into(),
})
}
};
self.handle_query(&request)
}
}
impl WasmMockQuerier {
pub fn handle_query(&self, request: &QueryRequest<TerraQueryWrapper>) -> QuerierResult {
match &request {
QueryRequest::Custom(TerraQueryWrapper { route, query_data }) => {
if &TerraRoute::Treasury == route {
match query_data {
TerraQuery::TaxRate {} => {
let res = TaxRateResponse {
rate: self.tax_querier.rate,
};
SystemResult::Ok(ContractResult::from(to_binary(&res)))
}
TerraQuery::TaxCap { denom } => {
let cap = self
.tax_querier
.caps
.get(denom)
.copied()
.unwrap_or_default();
let res = TaxCapResponse { cap };
SystemResult::Ok(ContractResult::from(to_binary(&res)))
}
_ => panic!("DO NOT ENTER HERE"),
}
} else {
panic!("DO NOT ENTER HERE")
}
}
QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: _,
msg,
}) => match from_binary(msg).unwrap() {
OracleQueryMsg::Price { base, quote } => {
match self.oracle_price_querier.oracle_price.get(&(base, quote)) {
Some(v) => {
SystemResult::Ok(ContractResult::from(to_binary(&PriceResponse {
rate: v.0,
last_updated_base: v.1,
last_updated_quote: v.2,
})))
}
None => SystemResult::Err(SystemError::InvalidRequest {
error: "No oracle price exists".to_string(),
request: msg.as_slice().into(),
}),
}
}
_ => panic!("DO NOT ENTER HERE"),
},
_ => self.base.handle_query(request),
}
}
}
impl WasmMockQuerier {
pub fn new(base: MockQuerier<TerraQueryWrapper>) -> Self {
WasmMockQuerier {
base,
tax_querier: TaxQuerier::default(),
oracle_price_querier: OraclePriceQuerier::default(),
}
}
pub fn with_tax(&mut self, rate: Decimal, caps: &[(&String, &Uint128)]) {
self.tax_querier = TaxQuerier::new(rate, caps);
}
#[allow(clippy::type_complexity)]
pub fn with_oracle_price(
&mut self,
oracle_price: &[(&(String, String), &(Decimal256, u64, u64))],
) {
self.oracle_price_querier = OraclePriceQuerier::new(oracle_price);
}
}