Skip to main content

nym_validator_client/nyxd/contract_traits/
vesting_query_client.rs

1// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::collect_paged;
5use crate::nyxd::coin::Coin;
6use crate::nyxd::contract_traits::NymContractsProvider;
7use crate::nyxd::error::NyxdError;
8use crate::nyxd::CosmWasmClient;
9use async_trait::async_trait;
10use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
11use nym_contracts_common::ContractBuildInformation;
12use nym_mixnet_contract_common::NodeId;
13use nym_vesting_contract_common::{
14    messages::QueryMsg as VestingQueryMsg, Account, AccountVestingCoins, AccountsResponse,
15    AllDelegationsResponse, BaseVestingAccountInfo, DelegationTimesResponse,
16    OriginalVestingResponse, Period, PledgeData, VestingCoinsResponse, VestingDelegation,
17};
18use serde::Deserialize;
19
20#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
21#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
22pub trait VestingQueryClient {
23    async fn query_vesting_contract<T>(&self, query: VestingQueryMsg) -> Result<T, NyxdError>
24    where
25        for<'a> T: Deserialize<'a>;
26
27    async fn get_vesting_contract_version(&self) -> Result<ContractBuildInformation, NyxdError> {
28        self.query_vesting_contract(VestingQueryMsg::GetContractVersion {})
29            .await
30    }
31
32    async fn get_vesting_contract_cw2_version(&self) -> Result<cw2::ContractVersion, NyxdError> {
33        self.query_vesting_contract(VestingQueryMsg::GetCW2ContractVersion {})
34            .await
35    }
36
37    async fn get_all_accounts_paged(
38        &self,
39        start_next_after: Option<String>,
40        limit: Option<u32>,
41    ) -> Result<AccountsResponse, NyxdError> {
42        self.query_vesting_contract(VestingQueryMsg::GetAccountsPaged {
43            start_next_after,
44            limit,
45        })
46        .await
47    }
48
49    async fn get_all_accounts_vesting_coins_paged(
50        &self,
51        start_next_after: Option<String>,
52        limit: Option<u32>,
53    ) -> Result<VestingCoinsResponse, NyxdError> {
54        self.query_vesting_contract(VestingQueryMsg::GetAccountsVestingCoinsPaged {
55            start_next_after,
56            limit,
57        })
58        .await
59    }
60
61    async fn locked_coins(
62        &self,
63        vesting_account_address: &str,
64        block_time: Option<Timestamp>,
65    ) -> Result<Coin, NyxdError> {
66        self.query_vesting_contract::<CosmWasmCoin>(VestingQueryMsg::LockedCoins {
67            vesting_account_address: vesting_account_address.to_string(),
68            block_time,
69        })
70        .await
71        .map(Into::into)
72    }
73
74    async fn spendable_coins(
75        &self,
76        vesting_account_address: &str,
77        block_time: Option<Timestamp>,
78    ) -> Result<Coin, NyxdError> {
79        self.query_vesting_contract::<CosmWasmCoin>(VestingQueryMsg::SpendableCoins {
80            vesting_account_address: vesting_account_address.to_string(),
81            block_time,
82        })
83        .await
84        .map(Into::into)
85    }
86
87    async fn vested_coins(
88        &self,
89        vesting_account_address: &str,
90        block_time: Option<Timestamp>,
91    ) -> Result<Coin, NyxdError> {
92        self.query_vesting_contract::<CosmWasmCoin>(VestingQueryMsg::GetVestedCoins {
93            vesting_account_address: vesting_account_address.to_string(),
94            block_time,
95        })
96        .await
97        .map(Into::into)
98    }
99
100    async fn vesting_coins(
101        &self,
102        vesting_account_address: &str,
103        block_time: Option<Timestamp>,
104    ) -> Result<Coin, NyxdError> {
105        self.query_vesting_contract::<CosmWasmCoin>(VestingQueryMsg::GetVestingCoins {
106            vesting_account_address: vesting_account_address.to_string(),
107            block_time,
108        })
109        .await
110        .map(Into::into)
111    }
112
113    async fn vesting_start_time(
114        &self,
115        vesting_account_address: &str,
116    ) -> Result<Timestamp, NyxdError> {
117        self.query_vesting_contract(VestingQueryMsg::GetStartTime {
118            vesting_account_address: vesting_account_address.to_string(),
119        })
120        .await
121    }
122
123    async fn vesting_end_time(
124        &self,
125        vesting_account_address: &str,
126    ) -> Result<Timestamp, NyxdError> {
127        self.query_vesting_contract(VestingQueryMsg::GetEndTime {
128            vesting_account_address: vesting_account_address.to_string(),
129        })
130        .await
131    }
132
133    async fn original_vesting(
134        &self,
135        vesting_account_address: &str,
136    ) -> Result<OriginalVestingResponse, NyxdError> {
137        self.query_vesting_contract(VestingQueryMsg::GetOriginalVesting {
138            vesting_account_address: vesting_account_address.to_string(),
139        })
140        .await
141    }
142
143    async fn get_historical_vesting_staking_reward(
144        &self,
145        vesting_account_address: &str,
146    ) -> Result<Coin, NyxdError> {
147        self.query_vesting_contract::<CosmWasmCoin>(
148            VestingQueryMsg::GetHistoricalVestingStakingReward {
149                vesting_account_address: vesting_account_address.to_string(),
150            },
151        )
152        .await
153        .map(Into::into)
154    }
155
156    async fn get_spendable_vested_coins(
157        &self,
158        vesting_account_address: &str,
159    ) -> Result<Coin, NyxdError> {
160        self.query_vesting_contract::<CosmWasmCoin>(VestingQueryMsg::GetSpendableVestedCoins {
161            vesting_account_address: vesting_account_address.to_string(),
162        })
163        .await
164        .map(Into::into)
165    }
166
167    async fn get_spendable_reward_coins(
168        &self,
169        vesting_account_address: &str,
170    ) -> Result<Coin, NyxdError> {
171        self.query_vesting_contract::<CosmWasmCoin>(VestingQueryMsg::GetSpendableRewardCoins {
172            vesting_account_address: vesting_account_address.to_string(),
173        })
174        .await
175        .map(Into::into)
176    }
177
178    async fn get_delegated_coins(&self, vesting_account_address: &str) -> Result<Coin, NyxdError> {
179        self.query_vesting_contract::<CosmWasmCoin>(VestingQueryMsg::GetDelegatedCoins {
180            vesting_account_address: vesting_account_address.to_string(),
181        })
182        .await
183        .map(Into::into)
184    }
185
186    async fn get_pledged_coins(&self, vesting_account_address: &str) -> Result<Coin, NyxdError> {
187        self.query_vesting_contract::<CosmWasmCoin>(VestingQueryMsg::GetPledgedCoins {
188            vesting_account_address: vesting_account_address.to_string(),
189        })
190        .await
191        .map(Into::into)
192    }
193
194    async fn get_staked_coins(&self, vesting_account_address: &str) -> Result<Coin, NyxdError> {
195        self.query_vesting_contract::<CosmWasmCoin>(VestingQueryMsg::GetStakedCoins {
196            vesting_account_address: vesting_account_address.to_string(),
197        })
198        .await
199        .map(Into::into)
200    }
201
202    async fn get_withdrawn_coins(&self, vesting_account_address: &str) -> Result<Coin, NyxdError> {
203        self.query_vesting_contract::<CosmWasmCoin>(VestingQueryMsg::GetWithdrawnCoins {
204            vesting_account_address: vesting_account_address.to_string(),
205        })
206        .await
207        .map(Into::into)
208    }
209
210    async fn get_account(&self, address: &str) -> Result<Account, NyxdError> {
211        self.query_vesting_contract(VestingQueryMsg::GetAccount {
212            address: address.to_string(),
213        })
214        .await
215    }
216
217    async fn get_mixnode_pledge(&self, address: &str) -> Result<Option<PledgeData>, NyxdError> {
218        self.query_vesting_contract(VestingQueryMsg::GetMixnode {
219            address: address.to_string(),
220        })
221        .await
222    }
223
224    async fn get_gateway_pledge(&self, address: &str) -> Result<Option<PledgeData>, NyxdError> {
225        self.query_vesting_contract(VestingQueryMsg::GetGateway {
226            address: address.to_string(),
227        })
228        .await
229    }
230
231    async fn get_current_vesting_period(&self, address: &str) -> Result<Period, NyxdError> {
232        self.query_vesting_contract(VestingQueryMsg::GetCurrentVestingPeriod {
233            address: address.to_string(),
234        })
235        .await
236    }
237
238    async fn get_vesting_delegation(
239        &self,
240        address: &str,
241        mix_id: NodeId,
242        block_timestamp_secs: u64,
243    ) -> Result<VestingDelegation, NyxdError> {
244        self.query_vesting_contract(VestingQueryMsg::GetDelegation {
245            address: address.to_string(),
246            mix_id,
247            block_timestamp_secs,
248        })
249        .await
250    }
251
252    async fn get_total_delegation_amount(
253        &self,
254        address: &str,
255        mix_id: NodeId,
256    ) -> Result<Coin, NyxdError> {
257        self.query_vesting_contract(VestingQueryMsg::GetTotalDelegationAmount {
258            address: address.to_string(),
259            mix_id,
260        })
261        .await
262    }
263
264    async fn get_delegation_timestamps(
265        &self,
266        address: &str,
267        mix_id: NodeId,
268    ) -> Result<DelegationTimesResponse, NyxdError> {
269        self.query_vesting_contract(VestingQueryMsg::GetDelegationTimes {
270            address: address.to_string(),
271            mix_id,
272        })
273        .await
274    }
275
276    async fn get_all_vesting_delegations_paged(
277        &self,
278        start_after: Option<(u32, NodeId, u64)>,
279        limit: Option<u32>,
280    ) -> Result<AllDelegationsResponse, NyxdError> {
281        self.query_vesting_contract(VestingQueryMsg::GetAllDelegations { start_after, limit })
282            .await
283    }
284}
285
286#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
287#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
288pub trait PagedVestingQueryClient: VestingQueryClient {
289    async fn get_all_vesting_delegations(&self) -> Result<Vec<VestingDelegation>, NyxdError> {
290        collect_paged!(self, get_all_vesting_delegations_paged, delegations)
291    }
292
293    async fn get_all_accounts_info(&self) -> Result<Vec<BaseVestingAccountInfo>, NyxdError> {
294        collect_paged!(self, get_all_accounts_paged, accounts)
295    }
296
297    async fn get_all_accounts_vesting_coins(&self) -> Result<Vec<AccountVestingCoins>, NyxdError> {
298        collect_paged!(self, get_all_accounts_vesting_coins_paged, accounts)
299    }
300}
301
302#[async_trait]
303impl<T> PagedVestingQueryClient for T where T: VestingQueryClient {}
304
305#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
306#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
307impl<C> VestingQueryClient for C
308where
309    C: CosmWasmClient + NymContractsProvider + Send + Sync,
310{
311    async fn query_vesting_contract<T>(&self, query: VestingQueryMsg) -> Result<T, NyxdError>
312    where
313        for<'a> T: Deserialize<'a>,
314    {
315        let vesting_contract_address = &self
316            .vesting_contract_address()
317            .ok_or_else(|| NyxdError::unavailable_contract_address("vesting contract"))?;
318        self.query_contract_smart(vesting_contract_address, &query)
319            .await
320    }
321}
322
323#[cfg(test)]
324mod tests {
325    use super::*;
326    use crate::nyxd::contract_traits::tests::IgnoreValue;
327
328    // it's enough that this compiles and clippy is happy about it
329    #[allow(dead_code)]
330    fn all_query_variants_are_covered<C: VestingQueryClient + Send + Sync>(
331        client: C,
332        msg: VestingQueryMsg,
333    ) {
334        match msg {
335            VestingQueryMsg::GetContractVersion {} => {
336                client.get_vesting_contract_version().ignore()
337            }
338            VestingQueryMsg::GetCW2ContractVersion {} => {
339                client.get_vesting_contract_cw2_version().ignore()
340            }
341            VestingQueryMsg::GetAccountsPaged {
342                start_next_after,
343                limit,
344            } => client
345                .get_all_accounts_paged(start_next_after, limit)
346                .ignore(),
347            VestingQueryMsg::GetAccountsVestingCoinsPaged {
348                start_next_after,
349                limit,
350            } => client
351                .get_all_accounts_vesting_coins_paged(start_next_after, limit)
352                .ignore(),
353            VestingQueryMsg::LockedCoins {
354                vesting_account_address,
355                block_time,
356            } => client
357                .locked_coins(&vesting_account_address, block_time)
358                .ignore(),
359            VestingQueryMsg::SpendableCoins {
360                vesting_account_address,
361                block_time,
362            } => client
363                .spendable_coins(&vesting_account_address, block_time)
364                .ignore(),
365            VestingQueryMsg::GetVestedCoins {
366                vesting_account_address,
367                block_time,
368            } => client
369                .vested_coins(&vesting_account_address, block_time)
370                .ignore(),
371            VestingQueryMsg::GetVestingCoins {
372                vesting_account_address,
373                block_time,
374            } => client
375                .vesting_coins(&vesting_account_address, block_time)
376                .ignore(),
377            VestingQueryMsg::GetStartTime {
378                vesting_account_address,
379            } => client.vesting_start_time(&vesting_account_address).ignore(),
380            VestingQueryMsg::GetEndTime {
381                vesting_account_address,
382            } => client.vesting_end_time(&vesting_account_address).ignore(),
383            VestingQueryMsg::GetOriginalVesting {
384                vesting_account_address,
385            } => client.original_vesting(&vesting_account_address).ignore(),
386            VestingQueryMsg::GetHistoricalVestingStakingReward {
387                vesting_account_address,
388            } => client
389                .get_historical_vesting_staking_reward(&vesting_account_address)
390                .ignore(),
391            VestingQueryMsg::GetSpendableVestedCoins {
392                vesting_account_address,
393            } => client
394                .get_spendable_vested_coins(&vesting_account_address)
395                .ignore(),
396            VestingQueryMsg::GetSpendableRewardCoins {
397                vesting_account_address,
398            } => client
399                .get_spendable_reward_coins(&vesting_account_address)
400                .ignore(),
401            VestingQueryMsg::GetDelegatedCoins {
402                vesting_account_address,
403            } => client
404                .get_delegated_coins(&vesting_account_address)
405                .ignore(),
406            VestingQueryMsg::GetPledgedCoins {
407                vesting_account_address,
408            } => client.get_pledged_coins(&vesting_account_address).ignore(),
409            VestingQueryMsg::GetStakedCoins {
410                vesting_account_address,
411            } => client.get_staked_coins(&vesting_account_address).ignore(),
412            VestingQueryMsg::GetWithdrawnCoins {
413                vesting_account_address,
414            } => client
415                .get_withdrawn_coins(&vesting_account_address)
416                .ignore(),
417            VestingQueryMsg::GetAccount { address } => client.get_account(&address).ignore(),
418            VestingQueryMsg::GetMixnode { address } => client.get_mixnode_pledge(&address).ignore(),
419            VestingQueryMsg::GetGateway { address } => client.get_gateway_pledge(&address).ignore(),
420            VestingQueryMsg::GetCurrentVestingPeriod { address } => {
421                client.get_current_vesting_period(&address).ignore()
422            }
423            VestingQueryMsg::GetDelegation {
424                address,
425                mix_id,
426                block_timestamp_secs,
427            } => client
428                .get_vesting_delegation(&address, mix_id, block_timestamp_secs)
429                .ignore(),
430            VestingQueryMsg::GetTotalDelegationAmount { address, mix_id } => client
431                .get_total_delegation_amount(&address, mix_id)
432                .ignore(),
433            VestingQueryMsg::GetDelegationTimes { address, mix_id } => {
434                client.get_delegation_timestamps(&address, mix_id).ignore()
435            }
436            VestingQueryMsg::GetAllDelegations { start_after, limit } => client
437                .get_all_vesting_delegations_paged(start_after, limit)
438                .ignore(),
439        };
440    }
441}