use cosmwasm_std::Addr;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct Config {
pub owner: Addr,
pub council_address: Addr,
pub incentives_address: Addr,
pub safety_fund_address: Addr,
pub mars_token_address: Addr,
pub oracle_address: Addr,
pub protocol_admin_address: Addr,
pub protocol_rewards_collector_address: Addr,
pub red_bank_address: Addr,
pub staking_address: Addr,
pub treasury_address: Addr,
pub vesting_address: Addr,
pub xmars_token_address: Addr,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub enum MarsContract {
Council,
Incentives,
SafetyFund,
MarsToken,
Oracle,
ProtocolAdmin,
ProtocolRewardsCollector,
RedBank,
Staking,
Treasury,
Vesting,
XMarsToken,
}
pub mod msg {
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use super::MarsContract;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
pub owner: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
UpdateConfig { config: ConfigParams },
}
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, JsonSchema)]
pub struct ConfigParams {
pub owner: Option<String>,
pub council_address: Option<String>,
pub incentives_address: Option<String>,
pub safety_fund_address: Option<String>,
pub mars_token_address: Option<String>,
pub oracle_address: Option<String>,
pub protocol_admin_address: Option<String>,
pub protocol_rewards_collector_address: Option<String>,
pub red_bank_address: Option<String>,
pub staking_address: Option<String>,
pub treasury_address: Option<String>,
pub vesting_address: Option<String>,
pub xmars_token_address: Option<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
Config {},
Address { contract: MarsContract },
Addresses { contracts: Vec<MarsContract> },
}
}
pub mod helpers {
use super::msg::QueryMsg;
use super::MarsContract;
use crate::error::MarsError;
use cosmwasm_std::{to_binary, Addr, QuerierWrapper, QueryRequest, WasmQuery};
pub fn query_address(
querier: &QuerierWrapper,
address_provider_address: Addr,
contract: MarsContract,
) -> Result<Addr, MarsError> {
let query: Addr = querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: address_provider_address.to_string(),
msg: to_binary(&QueryMsg::Address {
contract: contract.clone(),
})?,
}))?;
if query == Addr::unchecked("") {
Err(MarsError::EmptyAddresses {
empty_addresses: vec![contract],
})
} else {
Ok(query)
}
}
pub fn query_addresses(
querier: &QuerierWrapper,
address_provider_address: Addr,
contracts: Vec<MarsContract>,
) -> Result<Vec<Addr>, MarsError> {
let expected_len = contracts.len();
let query: Vec<Addr> = querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: address_provider_address.to_string(),
msg: to_binary(&QueryMsg::Addresses {
contracts: contracts.clone(),
})?,
}))?;
if query.len() != expected_len {
return Err(MarsError::AddressesQueryWrongNumber {
expected: expected_len as u32,
actual: query.len() as u32,
});
}
let empty_addresses = query
.iter()
.zip(contracts)
.filter(|(address, _)| *address == &Addr::unchecked(""))
.map(|(_, contract)| contract)
.collect::<Vec<MarsContract>>();
if !empty_addresses.is_empty() {
Err(MarsError::EmptyAddresses { empty_addresses })
} else {
Ok(query)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::address_provider::msg::QueryMsg;
use crate::error::MarsError;
use cosmwasm_std::testing::{MockApi, MockStorage};
use cosmwasm_std::{
from_binary, from_slice, to_binary, Binary, ContractResult, OwnedDeps, Querier,
QuerierResult, QueryRequest, StdResult, SystemError, WasmQuery,
};
use terra_cosmwasm::TerraQueryWrapper;
#[test]
fn test_query_address() {
let deps = OwnedDeps {
storage: MockStorage::default(),
api: MockApi::default(),
querier: AddressProviderMockQuerier {},
};
{
let err = helpers::query_address(
&deps.as_ref().querier,
Addr::unchecked("address_provider"),
MarsContract::Incentives,
)
.unwrap_err();
assert_eq!(
err,
MarsError::EmptyAddresses {
empty_addresses: vec![MarsContract::Incentives]
}
);
}
{
let address = helpers::query_address(
&deps.as_ref().querier,
Addr::unchecked("address_provider"),
MarsContract::RedBank,
)
.unwrap();
assert_eq!(address, Addr::unchecked("red_bank"));
}
}
#[test]
fn test_query_addresses() {
let deps = OwnedDeps {
storage: MockStorage::default(),
api: MockApi::default(),
querier: AddressProviderMockQuerier {},
};
{
let err = helpers::query_addresses(
&deps.as_ref().querier,
Addr::unchecked("address_provider"),
vec![
MarsContract::ProtocolRewardsCollector,
MarsContract::RedBank,
MarsContract::Incentives,
],
)
.unwrap_err();
assert_eq!(
err,
MarsError::EmptyAddresses {
empty_addresses: vec![
MarsContract::ProtocolRewardsCollector,
MarsContract::Incentives
]
}
);
}
{
let addresses = helpers::query_addresses(
&deps.as_ref().querier,
Addr::unchecked("address_provider"),
vec![MarsContract::Vesting, MarsContract::RedBank],
)
.unwrap();
assert_eq!(
addresses,
vec![Addr::unchecked("vesting"), Addr::unchecked("red_bank")]
);
}
}
#[derive(Clone, Copy)]
pub struct AddressProviderMockQuerier {}
impl Querier for AddressProviderMockQuerier {
fn raw_query(&self, bin_request: &[u8]) -> QuerierResult {
let request: QueryRequest<TerraQueryWrapper> = match from_slice(bin_request) {
Ok(v) => v,
Err(e) => {
return Err(SystemError::InvalidRequest {
error: format!("Parsing query request: {}", e),
request: bin_request.into(),
})
.into()
}
};
self.handle_query(&request)
}
}
impl AddressProviderMockQuerier {
pub fn handle_query(&self, request: &QueryRequest<TerraQueryWrapper>) -> QuerierResult {
if let QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: _,
msg,
}) = request
{
let parse_address_provider_query: StdResult<QueryMsg> = from_binary(msg);
if let Ok(address_provider_query) = parse_address_provider_query {
let ret: ContractResult<Binary> = match address_provider_query {
QueryMsg::Address { contract } => {
to_binary(&get_contract_address(contract)).into()
}
QueryMsg::Addresses { contracts } => {
let addresses = contracts
.into_iter()
.map(get_contract_address)
.collect::<Vec<_>>();
to_binary(&addresses).into()
}
_ => panic!("[mock]: Unsupported address provider query"),
};
return Ok(ret).into();
}
}
panic!("[mock]: Unsupported wasm query");
}
}
fn get_contract_address(contract: MarsContract) -> Addr {
match contract {
MarsContract::Incentives => Addr::unchecked(""),
MarsContract::ProtocolRewardsCollector => Addr::unchecked(""),
MarsContract::Council => Addr::unchecked("council"),
MarsContract::SafetyFund => Addr::unchecked("safety_fund"),
MarsContract::MarsToken => Addr::unchecked("mars_token"),
MarsContract::Oracle => Addr::unchecked("oracle"),
MarsContract::ProtocolAdmin => Addr::unchecked("protocol_admin"),
MarsContract::RedBank => Addr::unchecked("red_bank"),
MarsContract::Staking => Addr::unchecked("staking"),
MarsContract::Treasury => Addr::unchecked("treasury"),
MarsContract::Vesting => Addr::unchecked("vesting"),
MarsContract::XMarsToken => Addr::unchecked("xmars_token"),
}
}
}