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
use crate::chain::error::ChainError;
use crate::chain::request::PaginationRequest;
use crate::clients::client::ClientAbciQuery;
use crate::modules::auth::model::Account;
use async_trait::async_trait;
use cosmrs::proto::cosmos::auth::v1beta1::{
    BaseAccount, QueryAccountRequest, QueryAccountResponse, QueryAccountsRequest,
    QueryAccountsResponse, QueryParamsRequest, QueryParamsResponse,
};
use cosmrs::proto::traits::Message;

use super::error::AccountError;
use super::model::{AccountResponse, AccountsResponse, Address, ParamsResponse};

impl<T> Auth for T where T: ClientAbciQuery {}

#[async_trait]
pub trait Auth: ClientAbciQuery + Sized {
    async fn auth_query_account(&self, address: Address) -> Result<AccountResponse, AccountError> {
        let req = QueryAccountRequest {
            address: address.into(),
        };

        let res = self
            .query::<_, QueryAccountResponse>(req, "/cosmos.auth.v1beta1.Query/Account")
            .await?;

        let account = res.account.ok_or(AccountError::Address {
            message: "Invalid account address".to_string(),
        })?;

        let base_account = BaseAccount::decode(account.value.as_slice())
            .map_err(ChainError::prost_proto_decoding)?;

        Ok(AccountResponse {
            account: base_account.try_into()?,
        })
    }

    async fn auth_query_accounts(
        &self,
        pagination: Option<PaginationRequest>,
    ) -> Result<AccountsResponse, AccountError> {
        let req = QueryAccountsRequest {
            pagination: pagination.map(Into::into),
        };

        let res = self
            .query::<_, QueryAccountsResponse>(req, "/cosmos.auth.v1beta1.Query/Accounts")
            .await?;

        let accounts: Vec<Account> = res
            .accounts
            .into_iter()
            .map(|a| {
                BaseAccount::decode(a.value.as_slice())
                    .map_err(ChainError::prost_proto_decoding)?
                    .try_into()
            })
            .collect::<Result<Vec<Account>, AccountError>>()?;

        Ok(AccountsResponse {
            accounts,
            next: res.pagination.map(Into::into),
        })
    }

    async fn auth_query_params(&self) -> Result<ParamsResponse, AccountError> {
        let req = QueryParamsRequest {};

        let res = self
            .query::<_, QueryParamsResponse>(req, "/cosmos.auth.v1beta1.Query/Params")
            .await?;

        Ok(ParamsResponse {
            params: res.params.map(Into::into),
        })
    }
}