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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// This file is part of Gear.

// Copyright (C) 2022-2024 Gear Technologies Inc.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

pub(crate) mod account_id;
mod block;

use super::{GearApi, Result};
use crate::Error;
use account_id::IntoAccountId32;
use gear_core::{ids::*, message::UserStoredMessage};
use gsdk::{
    ext::sp_core::{crypto::Ss58Codec, H256},
    metadata::runtime_types::{
        gear_common::storage::primitives::Interval, gear_core::message::user,
        pallet_balances::types::AccountData, pallet_gear_bank::pallet::BankAccount,
    },
};

impl GearApi {
    /// Get a message identified by `message_id` from the mailbox.
    pub async fn get_mailbox_message(
        &self,
        message_id: MessageId,
    ) -> Result<Option<(UserStoredMessage, Interval<u32>)>> {
        self.get_mailbox_account_message(self.0.account_id(), message_id)
            .await
    }

    /// Get a message identified by `message_id` from the `account_id`'s
    /// mailbox.
    pub async fn get_mailbox_account_message(
        &self,
        account_id: impl IntoAccountId32,
        message_id: MessageId,
    ) -> Result<Option<(UserStoredMessage, Interval<u32>)>> {
        let data: Option<(user::UserStoredMessage, Interval<u32>)> = self
            .0
            .api()
            .get_mailbox_account_message(account_id.into_account_id(), message_id)
            .await?;
        Ok(data.map(|(m, i)| (m.into(), i)))
    }

    /// Get up to `count` messages from the mailbox for
    /// the provided `account_id`.
    pub async fn get_mailbox_account_messages(
        &self,
        account_id: impl IntoAccountId32,
        count: u32,
    ) -> Result<Vec<(UserStoredMessage, Interval<u32>)>> {
        let data = self
            .0
            .api()
            .mailbox(Some(account_id.into_account_id()), count)
            .await?;
        Ok(data.into_iter().map(|(m, i)| (m.into(), i)).collect())
    }

    /// Get up to `count` messages from the mailbox.
    pub async fn get_mailbox_messages(
        &self,
        count: u32,
    ) -> Result<Vec<(UserStoredMessage, Interval<u32>)>> {
        self.get_mailbox_account_messages(self.0.account_id(), count)
            .await
    }

    /// Get account data by `account_id`.
    pub(crate) async fn account_data(
        &self,
        account_id: impl IntoAccountId32,
    ) -> Result<AccountData<u128>> {
        self.account_data_at(account_id, None).await
    }

    /// Get account data by `account_id` at specified block.
    pub(crate) async fn account_data_at(
        &self,
        account_id: impl IntoAccountId32,
        block_hash: Option<H256>,
    ) -> Result<AccountData<u128>> {
        Ok(self
            .0
            .api()
            .info_at(&account_id.into_account_id().to_ss58check(), block_hash)
            .await?
            .data)
    }

    /// Get bank account data by `account_id` at specified block.
    pub(crate) async fn bank_data_at(
        &self,
        account_id: impl IntoAccountId32,
        block_hash: Option<H256>,
    ) -> Result<BankAccount<u128>> {
        Ok(self
            .0
            .api()
            .bank_info_at(account_id.into_account_id(), block_hash)
            .await?)
    }

    /// Get the total balance of the account identified by `account_id`.
    ///
    /// Total balance includes free and reserved funds.
    pub async fn total_balance(&self, account_id: impl IntoAccountId32) -> Result<u128> {
        let data = self.account_data(account_id).await?;

        data.free
            .checked_add(data.reserved)
            .ok_or(Error::BalanceOverflow)
    }

    /// Get the free funds balance of the account identified by `account_id`.
    pub async fn free_balance(&self, account_id: impl IntoAccountId32) -> Result<u128> {
        let data = self.account_data(account_id).await?;

        Ok(data.free)
    }

    /// Get the reserved funds balance of the account identified by
    /// `account_id`.
    pub async fn reserved_balance(&self, account_id: impl IntoAccountId32) -> Result<u128> {
        let data = self.account_data(account_id).await?;

        Ok(data.reserved)
    }
}