1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! Contains utilities and query endpoints for use with the Cosmos bank module
//!
use super::PAGE;
use crate::error::CosmosGrpcError;
use crate::{Address, Coin, Contact};
use cosmos_sdk_proto::cosmos::bank::v1beta1::query_client::QueryClient as BankQueryClient;
use cosmos_sdk_proto::cosmos::bank::v1beta1::{
    Metadata, QueryDenomMetadataRequest, QueryDenomsMetadataRequest, QuerySupplyOfRequest,
    QueryTotalSupplyRequest,
};
use cosmos_sdk_proto::cosmos::bank::v1beta1::{QueryAllBalancesRequest, QueryBalanceRequest};

impl Contact {
    /// gets the total supply of all coins on chain
    pub async fn query_total_supply(&self) -> Result<Vec<Coin>, CosmosGrpcError> {
        let mut grpc = BankQueryClient::connect(self.url.clone())
            .await?
            .accept_gzip();
        let res = grpc
            .total_supply(QueryTotalSupplyRequest { pagination: PAGE })
            .await?
            .into_inner();
        let mut out = Vec::new();
        for val in res.supply {
            out.push(val.into())
        }
        Ok(out)
    }

    /// gets the supply of an individual token
    pub async fn query_supply_of(&self, denom: String) -> Result<Option<Coin>, CosmosGrpcError> {
        let mut grpc = BankQueryClient::connect(self.url.clone())
            .await?
            .accept_gzip();
        let res = grpc
            .supply_of(QuerySupplyOfRequest { denom })
            .await?
            .into_inner();
        match res.amount {
            Some(v) => Ok(Some(v.into())),
            None => Ok(None),
        }
    }

    /// Gets the denom metadata for every token type on the chain
    pub async fn get_all_denoms_metadata(&self) -> Result<Vec<Metadata>, CosmosGrpcError> {
        let mut grpc = BankQueryClient::connect(self.url.clone())
            .await?
            .accept_gzip();
        let res = grpc
            .denoms_metadata(QueryDenomsMetadataRequest { pagination: PAGE })
            .await?
            .into_inner();
        Ok(res.metadatas)
    }

    /// Gets the denom metadata for a specific token
    pub async fn get_denom_metadata(
        &self,
        denom: String,
    ) -> Result<Option<Metadata>, CosmosGrpcError> {
        let mut grpc = BankQueryClient::connect(self.url.clone())
            .await?
            .accept_gzip();
        let res = grpc
            .denom_metadata(QueryDenomMetadataRequest { denom })
            .await?
            .into_inner();
        Ok(res.metadata)
    }

    /// Gets the coin balances for an individual account
    pub async fn get_balances(&self, address: Address) -> Result<Vec<Coin>, CosmosGrpcError> {
        let mut bankrpc = BankQueryClient::connect(self.url.clone())
            .await?
            .accept_gzip();
        let res = bankrpc
            .all_balances(QueryAllBalancesRequest {
                // chain prefix is validated as part of this client, so this can't
                // panic
                address: address.to_bech32(&self.chain_prefix).unwrap(),
                pagination: PAGE,
            })
            .await?
            .into_inner();
        let balances = res.balances;
        let mut ret = Vec::new();
        for value in balances {
            ret.push(value.into());
        }
        Ok(ret)
    }

    /// Gets the balance of a single for an individual account
    pub async fn get_balance(
        &self,
        address: Address,
        denom: String,
    ) -> Result<Option<Coin>, CosmosGrpcError> {
        let mut bankrpc = BankQueryClient::connect(self.url.clone())
            .await?
            .accept_gzip();
        let res = bankrpc
            .balance(QueryBalanceRequest {
                // chain prefix is validated as part of this client, so this can't
                // panic
                address: address.to_bech32(&self.chain_prefix).unwrap(),
                denom,
            })
            .await?
            .into_inner();
        match res.balance {
            Some(v) => Ok(Some(v.into())),
            None => Ok(None),
        }
    }
}