nym_validator_client/nyxd/contract_traits/
group_query_client.rs1use crate::nyxd::contract_traits::NymContractsProvider;
5use crate::nyxd::error::NyxdError;
6use crate::nyxd::CosmWasmClient;
7use async_trait::async_trait;
8use cw4::{Member, MemberListResponse, MemberResponse, TotalWeightResponse};
9use nym_group_contract_common::msg::QueryMsg as GroupQueryMsg;
10use serde::Deserialize;
11
12#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
13#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
14pub trait GroupQueryClient {
15 async fn query_group_contract<T>(&self, query: GroupQueryMsg) -> Result<T, NyxdError>
16 where
17 for<'a> T: Deserialize<'a>;
18
19 async fn admin(&self) -> Result<cw_controllers::AdminResponse, NyxdError> {
20 self.query_group_contract(GroupQueryMsg::Admin {}).await
21 }
22
23 async fn total_weight(&self, at_height: Option<u64>) -> Result<TotalWeightResponse, NyxdError> {
24 self.query_group_contract(GroupQueryMsg::TotalWeight { at_height })
25 .await
26 }
27
28 async fn list_members_paged(
29 &self,
30 start_after: Option<String>,
31 limit: Option<u32>,
32 ) -> Result<MemberListResponse, NyxdError> {
33 self.query_group_contract(GroupQueryMsg::ListMembers { start_after, limit })
34 .await
35 }
36
37 async fn member(
38 &self,
39 addr: String,
40 at_height: Option<u64>,
41 ) -> Result<MemberResponse, NyxdError> {
42 self.query_group_contract(GroupQueryMsg::Member { addr, at_height })
43 .await
44 }
45
46 async fn hooks(&self) -> Result<cw_controllers::HooksResponse, NyxdError> {
47 self.query_group_contract(GroupQueryMsg::Hooks {}).await
48 }
49}
50
51#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
52#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
53pub trait PagedGroupQueryClient: GroupQueryClient {
54 async fn get_all_members(&self) -> Result<Vec<Member>, NyxdError> {
56 let mut members = Vec::new();
57 let mut start_after = None;
58
59 loop {
60 let mut paged_response = self.list_members_paged(start_after.take(), None).await?;
61
62 let last_id = paged_response.members.last().map(|mem| mem.addr.clone());
63 members.append(&mut paged_response.members);
64
65 if let Some(start_after_res) = last_id {
66 start_after = Some(start_after_res)
67 } else {
68 break;
69 }
70 }
71
72 Ok(members)
73 }
74}
75
76#[async_trait]
77impl<T> PagedGroupQueryClient for T where T: GroupQueryClient {}
78
79#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
80#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
81impl<C> GroupQueryClient for C
82where
83 C: CosmWasmClient + NymContractsProvider + Send + Sync,
84{
85 async fn query_group_contract<T>(&self, query: GroupQueryMsg) -> Result<T, NyxdError>
86 where
87 for<'a> T: Deserialize<'a>,
88 {
89 let group_contract_address = &self
90 .group_contract_address()
91 .ok_or_else(|| NyxdError::unavailable_contract_address("group contract"))?;
92 self.query_contract_smart(group_contract_address, &query)
93 .await
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use crate::nyxd::contract_traits::tests::IgnoreValue;
101
102 #[allow(dead_code)]
104 fn all_query_variants_are_covered<C: GroupQueryClient + Send + Sync>(
105 client: C,
106 msg: GroupQueryMsg,
107 ) {
108 match msg {
109 GroupQueryMsg::Admin {} => client.admin().ignore(),
110 GroupQueryMsg::TotalWeight { at_height } => client.total_weight(at_height).ignore(),
111 GroupQueryMsg::ListMembers { start_after, limit } => {
112 client.list_members_paged(start_after, limit).ignore()
113 }
114 GroupQueryMsg::Member { addr, at_height } => client.member(addr, at_height).ignore(),
115 GroupQueryMsg::Hooks {} => client.hooks().ignore(),
116 };
117 }
118}