use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use cosmwasm_std::{
from_slice, to_binary, to_vec, Binary, CanonicalAddr, ContractResult, CosmosMsg, Empty,
HumanAddr, QuerierWrapper, QueryRequest, StdError, StdResult, SystemResult, WasmMsg, WasmQuery,
};
use crate::msg::Cw4ExecuteMsg;
use crate::query::HooksResponse;
use crate::{
member_key, AdminResponse, Cw4QueryMsg, Member, MemberListResponse, MemberResponse, TOTAL_KEY,
};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct Cw4Contract(pub HumanAddr);
impl Cw4Contract {
pub fn new(addr: HumanAddr) -> Self {
Cw4Contract(addr)
}
pub fn addr(&self) -> HumanAddr {
self.0.clone()
}
fn encode_msg(&self, msg: Cw4ExecuteMsg) -> StdResult<CosmosMsg> {
Ok(WasmMsg::Execute {
contract_addr: self.addr(),
msg: to_binary(&msg)?,
send: vec![],
}
.into())
}
pub fn add_hook(&self, addr: HumanAddr) -> StdResult<CosmosMsg> {
let msg = Cw4ExecuteMsg::AddHook { addr };
self.encode_msg(msg)
}
pub fn remove_hook(&self, addr: HumanAddr) -> StdResult<CosmosMsg> {
let msg = Cw4ExecuteMsg::AddHook { addr };
self.encode_msg(msg)
}
pub fn update_admin<T: Into<HumanAddr>>(
&self,
admin: Option<HumanAddr>,
) -> StdResult<CosmosMsg> {
let msg = Cw4ExecuteMsg::UpdateAdmin { admin };
self.encode_msg(msg)
}
fn encode_smart_query(&self, msg: Cw4QueryMsg) -> StdResult<QueryRequest<Empty>> {
Ok(WasmQuery::Smart {
contract_addr: self.addr(),
msg: to_binary(&msg)?,
}
.into())
}
fn encode_raw_query<T: Into<Binary>>(&self, key: T) -> QueryRequest<Empty> {
WasmQuery::Raw {
contract_addr: self.addr(),
key: key.into(),
}
.into()
}
pub fn hooks(&self, querier: &QuerierWrapper) -> StdResult<Vec<HumanAddr>> {
let query = self.encode_smart_query(Cw4QueryMsg::Hooks {})?;
let res: HooksResponse = querier.query(&query)?;
Ok(res.hooks)
}
pub fn total_weight(&self, querier: &QuerierWrapper) -> StdResult<u64> {
let query = self.encode_raw_query(TOTAL_KEY.as_bytes());
querier.query(&query)
}
pub fn is_member(
&self,
querier: &QuerierWrapper,
addr: &CanonicalAddr,
) -> StdResult<Option<u64>> {
let path = member_key(addr.as_slice());
let query = self.encode_raw_query(path);
let raw = to_vec(&query)?;
match querier.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 {
from_slice(&value)
}
}
}
}
pub fn member_at_height(
&self,
querier: &QuerierWrapper,
member: HumanAddr,
height: u64,
) -> StdResult<Option<u64>> {
let query = self.encode_smart_query(Cw4QueryMsg::Member {
addr: member,
at_height: Some(height),
})?;
let res: MemberResponse = querier.query(&query)?;
Ok(res.weight)
}
pub fn list_members(
&self,
querier: &QuerierWrapper,
start_after: Option<HumanAddr>,
limit: Option<u32>,
) -> StdResult<Vec<Member>> {
let query = self.encode_smart_query(Cw4QueryMsg::ListMembers { start_after, limit })?;
let res: MemberListResponse = querier.query(&query)?;
Ok(res.members)
}
pub fn admin(&self, querier: &QuerierWrapper) -> StdResult<Option<HumanAddr>> {
let query = self.encode_smart_query(Cw4QueryMsg::Admin {})?;
let res: AdminResponse = querier.query(&query)?;
Ok(res.admin)
}
}