Skip to main content

cw_orch_daemon/queriers/
bank.rs

1use crate::{cosmos_modules, error::DaemonError, senders::query::QuerySender, DaemonBase};
2use cosmrs::proto::cosmos::base::query::v1beta1::PageRequest;
3use cosmwasm_std::{Addr, Coin, StdError};
4use cw_orch_core::environment::{BankQuerier, Querier, QuerierGetter};
5use tokio::runtime::Handle;
6use tonic::transport::Channel;
7
8/// Queries for Cosmos Bank Module
9/// All the async function are prefixed with `_`
10pub struct Bank {
11    pub channel: Channel,
12    pub rt_handle: Option<Handle>,
13}
14
15impl Bank {
16    pub fn new<Sender: QuerySender>(daemon: &DaemonBase<Sender>) -> Self {
17        Self {
18            channel: daemon.channel(),
19            rt_handle: Some(daemon.rt_handle.clone()),
20        }
21    }
22    pub fn new_async(channel: Channel) -> Self {
23        Self {
24            channel,
25            rt_handle: None,
26        }
27    }
28}
29
30impl Querier for Bank {
31    type Error = DaemonError;
32}
33
34impl<Sender: QuerySender> QuerierGetter<Bank> for DaemonBase<Sender> {
35    fn querier(&self) -> Bank {
36        Bank::new(self)
37    }
38}
39
40impl Bank {
41    /// Query the bank balance of a given address
42    /// If denom is None, returns all balances
43    pub async fn _balance(
44        &self,
45        address: &Addr,
46        denom: Option<String>,
47    ) -> Result<Vec<Coin>, DaemonError> {
48        use cosmos_modules::bank::query_client::QueryClient;
49        match denom {
50            Some(denom) => {
51                let mut client: QueryClient<Channel> = QueryClient::new(self.channel.clone());
52                let request = cosmos_modules::bank::QueryBalanceRequest {
53                    address: address.to_string(),
54                    denom,
55                };
56                let resp = client.balance(request).await?.into_inner();
57                let coin = resp.balance.unwrap();
58                Ok(vec![cosmrs_to_cosmwasm_coin(coin)?])
59            }
60            None => {
61                let mut client: QueryClient<Channel> = QueryClient::new(self.channel.clone());
62                let request = cosmos_modules::bank::QueryAllBalancesRequest {
63                    address: address.to_string(),
64                    ..Default::default()
65                };
66                let resp = client.all_balances(request).await?.into_inner();
67                Ok(cosmrs_to_cosmwasm_coins(resp.balances)?)
68            }
69        }
70    }
71
72    /// Query spendable balance for address
73    pub async fn _spendable_balances(&self, address: &Addr) -> Result<Vec<Coin>, DaemonError> {
74        let spendable_balances: cosmos_modules::bank::QuerySpendableBalancesResponse = cosmos_query!(
75            self,
76            bank,
77            spendable_balances,
78            QuerySpendableBalancesRequest {
79                address: address.to_string(),
80                pagination: None,
81            }
82        );
83        Ok(cosmrs_to_cosmwasm_coins(spendable_balances.balances)?)
84    }
85
86    /// Query total supply in the bank
87    pub async fn _total_supply(&self) -> Result<Vec<Coin>, DaemonError> {
88        let total_supply: cosmos_modules::bank::QueryTotalSupplyResponse = cosmos_query!(
89            self,
90            bank,
91            total_supply,
92            QueryTotalSupplyRequest { pagination: None }
93        );
94        Ok(cosmrs_to_cosmwasm_coins(total_supply.supply)?)
95    }
96
97    /// Query total supply in the bank for a denom
98    pub async fn _supply_of(&self, denom: impl Into<String>) -> Result<Coin, DaemonError> {
99        let supply_of: cosmos_modules::bank::QuerySupplyOfResponse = cosmos_query!(
100            self,
101            bank,
102            supply_of,
103            QuerySupplyOfRequest {
104                denom: denom.into()
105            }
106        );
107        Ok(cosmrs_to_cosmwasm_coin(supply_of.amount.unwrap())?)
108    }
109
110    /// Query params
111    pub async fn _params(&self) -> Result<cosmos_modules::bank::Params, DaemonError> {
112        let params: cosmos_modules::bank::QueryParamsResponse =
113            cosmos_query!(self, bank, params, QueryParamsRequest {});
114        Ok(params.params.unwrap())
115    }
116
117    /// Query denom metadata
118    pub async fn _denom_metadata(
119        &self,
120        denom: impl Into<String>,
121    ) -> Result<cosmos_modules::bank::Metadata, DaemonError> {
122        let denom_metadata: cosmos_modules::bank::QueryDenomMetadataResponse = cosmos_query!(
123            self,
124            bank,
125            denom_metadata,
126            QueryDenomMetadataRequest {
127                denom: denom.into()
128            }
129        );
130        Ok(denom_metadata.metadata.unwrap())
131    }
132
133    /// Query denoms metadata with pagination
134    ///
135    /// see [PageRequest] for pagination
136    pub async fn _denoms_metadata(
137        &self,
138        pagination: Option<PageRequest>,
139    ) -> Result<Vec<cosmos_modules::bank::Metadata>, DaemonError> {
140        let denoms_metadata: cosmos_modules::bank::QueryDenomsMetadataResponse = cosmos_query!(
141            self,
142            bank,
143            denoms_metadata,
144            QueryDenomsMetadataRequest {
145                pagination: pagination
146            }
147        );
148        Ok(denoms_metadata.metadatas)
149    }
150}
151
152pub fn cosmrs_to_cosmwasm_coin(
153    c: cosmrs::proto::cosmos::base::v1beta1::Coin,
154) -> Result<Coin, StdError> {
155    Ok(Coin {
156        amount: c.amount.parse()?,
157        denom: c.denom,
158    })
159}
160
161pub fn cosmrs_to_cosmwasm_coins(
162    c: Vec<cosmrs::proto::cosmos::base::v1beta1::Coin>,
163) -> Result<Vec<Coin>, StdError> {
164    c.into_iter().map(cosmrs_to_cosmwasm_coin).collect()
165}
166impl BankQuerier for Bank {
167    fn balance(
168        &self,
169        address: &Addr,
170        denom: Option<String>,
171    ) -> Result<Vec<cosmwasm_std::Coin>, Self::Error> {
172        self.rt_handle
173            .as_ref()
174            .ok_or(DaemonError::QuerierNeedRuntime)?
175            .block_on(self._balance(address, denom))
176    }
177
178    fn total_supply(&self) -> Result<Vec<cosmwasm_std::Coin>, Self::Error> {
179        self.rt_handle
180            .as_ref()
181            .ok_or(DaemonError::QuerierNeedRuntime)?
182            .block_on(self._total_supply())
183    }
184
185    fn supply_of(&self, denom: impl Into<String>) -> Result<cosmwasm_std::Coin, Self::Error> {
186        self.rt_handle
187            .as_ref()
188            .ok_or(DaemonError::QuerierNeedRuntime)?
189            .block_on(self._supply_of(denom))
190    }
191}