Skip to main content

nym_validator_client/nyxd/contract_traits/
group_query_client.rs

1// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use 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    // can't use the macro due to different paging behaviour
55    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    // it's enough that this compiles and clippy is happy about it
103    #[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}