1use cosmwasm_schema::cw_serde;
2use cosmwasm_std::{
3 to_json_binary, Addr, CosmosMsg, CustomQuery, QuerierWrapper, QueryRequest, StdResult, WasmMsg,
4 WasmQuery,
5};
6
7use crate::msg::Cw4ExecuteMsg;
8use crate::query::HooksResponse;
9use crate::{
10 AdminResponse, Cw4QueryMsg, Member, MemberListResponse, MemberResponse, MEMBERS_KEY, TOTAL_KEY,
11};
12use cw_storage_plus::{Item, Map};
13
14#[cw_serde]
19pub struct Cw4Contract(pub Addr);
20
21impl Cw4Contract {
22 pub fn new(addr: Addr) -> Self {
23 Cw4Contract(addr)
24 }
25
26 pub fn addr(&self) -> Addr {
27 self.0.clone()
28 }
29
30 fn encode_msg(&self, msg: Cw4ExecuteMsg) -> StdResult<CosmosMsg> {
31 Ok(WasmMsg::Execute {
32 contract_addr: self.addr().into(),
33 msg: to_json_binary(&msg)?,
34 funds: vec![],
35 }
36 .into())
37 }
38
39 pub fn add_hook<T: Into<String>>(&self, addr: T) -> StdResult<CosmosMsg> {
40 let msg = Cw4ExecuteMsg::AddHook { addr: addr.into() };
41 self.encode_msg(msg)
42 }
43
44 pub fn remove_hook<T: Into<String>>(&self, addr: T) -> StdResult<CosmosMsg> {
45 let msg = Cw4ExecuteMsg::RemoveHook { addr: addr.into() };
46 self.encode_msg(msg)
47 }
48
49 pub fn update_admin<T: Into<String>>(&self, admin: Option<T>) -> StdResult<CosmosMsg> {
50 let msg = Cw4ExecuteMsg::UpdateAdmin {
51 admin: admin.map(|x| x.into()),
52 };
53 self.encode_msg(msg)
54 }
55
56 fn encode_smart_query<Q: CustomQuery>(&self, msg: Cw4QueryMsg) -> StdResult<QueryRequest<Q>> {
57 Ok(WasmQuery::Smart {
58 contract_addr: self.addr().into(),
59 msg: to_json_binary(&msg)?,
60 }
61 .into())
62 }
63
64 pub fn hooks<Q: CustomQuery>(&self, querier: &QuerierWrapper<Q>) -> StdResult<Vec<String>> {
66 let query = self.encode_smart_query(Cw4QueryMsg::Hooks {})?;
67 let res: HooksResponse = querier.query(&query)?;
68 Ok(res.hooks)
69 }
70
71 pub fn total_weight(&self, querier: &QuerierWrapper) -> StdResult<u64> {
73 Item::new(TOTAL_KEY).query(querier, self.addr())
74 }
75
76 pub fn is_member(
78 &self,
79 querier: &QuerierWrapper,
80 member: &Addr,
81 height: Option<u64>,
82 ) -> StdResult<Option<u64>> {
83 match height {
84 Some(height) => self.member_at_height(querier, member.to_string(), height.into()),
85 None => Map::new(MEMBERS_KEY).query(querier, self.addr(), member),
86 }
87 }
88
89 pub fn is_voting_member(
92 &self,
93 querier: &QuerierWrapper,
94 member: &Addr,
95 height: impl Into<Option<u64>>,
96 ) -> StdResult<Option<u64>> {
97 if let Some(weight) = self.member_at_height(querier, member.to_string(), height.into())? {
98 if weight >= 1 {
99 return Ok(Some(weight));
100 }
101 }
102 Ok(None)
103 }
104
105 pub fn member_at_height(
107 &self,
108 querier: &QuerierWrapper,
109 member: impl Into<String>,
110 at_height: Option<u64>,
111 ) -> StdResult<Option<u64>> {
112 let query = self.encode_smart_query(Cw4QueryMsg::Member {
113 addr: member.into(),
114 at_height,
115 })?;
116 let res: MemberResponse = querier.query(&query)?;
117 Ok(res.weight)
118 }
119
120 pub fn list_members(
121 &self,
122 querier: &QuerierWrapper,
123 start_after: Option<String>,
124 limit: Option<u32>,
125 ) -> StdResult<Vec<Member>> {
126 let query = self.encode_smart_query(Cw4QueryMsg::ListMembers { start_after, limit })?;
127 let res: MemberListResponse = querier.query(&query)?;
128 Ok(res.members)
129 }
130
131 pub fn admin(&self, querier: &QuerierWrapper) -> StdResult<Option<String>> {
133 let query = self.encode_smart_query(Cw4QueryMsg::Admin {})?;
134 let res: AdminResponse = querier.query(&query)?;
135 Ok(res.admin)
136 }
137}