cosm_utils/modules/bank/
model.rs

1use std::fmt;
2
3use cosmrs::proto::cosmos::bank::v1beta1::{
4    DenomUnit as ProtoDenomUnit, Metadata, MsgSend, Params as ProtoParams,
5    SendEnabled as ProtoSendEnabled,
6};
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9
10use crate::chain::coin::Denom;
11use crate::chain::msg::Msg;
12use crate::{
13    chain::{coin::Coin, error::ChainError, request::PaginationResponse},
14    modules::auth::model::Address,
15};
16
17use super::error::BankError;
18
19#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
20pub struct BalanceResponse {
21    pub balance: Coin,
22}
23
24#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
25pub struct BalancesResponse {
26    pub balances: Vec<Coin>,
27
28    pub next: Option<PaginationResponse>,
29}
30
31#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
32pub struct DenomMetadataResponse {
33    pub meta: Option<DenomMetadata>,
34}
35
36#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
37pub struct DenomsMetadataResponse {
38    pub metas: Vec<DenomMetadata>,
39
40    pub next: Option<PaginationResponse>,
41}
42
43#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
44pub struct DenomMetadata {
45    pub description: String,
46
47    pub denom_units: Vec<DenomUnit>,
48
49    /// base represents the base denom (should be the DenomUnit with exponent = 0).
50    pub base: String,
51
52    /// display indicates the suggested denom string that should be displayed in clients.
53    pub display: String,
54
55    /// name defines the name of the token (eg: Cosmos Atom)
56    ///
57    /// Since: cosmos-sdk 0.43
58    pub name: String,
59
60    /// symbol is the token symbol usually shown on exchanges (eg: ATOM).
61    /// This can be the same as the display.
62    ///
63    /// Since: cosmos-sdk 0.43
64    pub symbol: String,
65    pub uri: String,
66    pub uri_hash: String,
67}
68
69impl TryFrom<Metadata> for DenomMetadata {
70    type Error = ChainError;
71
72    fn try_from(meta: Metadata) -> Result<Self, Self::Error> {
73        Ok(Self {
74            description: meta.description,
75            denom_units: meta
76                .denom_units
77                .into_iter()
78                .map(TryInto::try_into)
79                .collect::<Result<Vec<_>, _>>()?,
80            base: meta.base,
81            display: meta.display,
82            name: meta.name,
83            symbol: meta.symbol,
84            uri: meta.uri,
85            uri_hash: meta.uri_hash,
86        })
87    }
88}
89
90impl From<DenomMetadata> for Metadata {
91    fn from(meta: DenomMetadata) -> Self {
92        Self {
93            description: meta.description,
94            denom_units: meta.denom_units.into_iter().map(Into::into).collect(),
95            base: meta.base,
96            display: meta.display,
97            name: meta.name,
98            symbol: meta.symbol,
99            uri: meta.uri,
100            uri_hash: meta.uri_hash,
101        }
102    }
103}
104
105#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
106pub struct DenomUnit {
107    /// denom represents the string name of the given denom unit (e.g uatom).
108    pub denom: Denom,
109
110    /// exponent represents the power of 10 exponent that one must raise the base_denom to in order to equal the given DenomUnit's denom.
111    /// 1 denom = 1^exponent base_denom
112    /// (e.g. with a base_denom of uatom, one can create a DenomUnit of 'atom' with exponent = 6, thus: 1 atom = 10^6 uatom).
113    pub exponent: u32,
114
115    /// aliases is a list of string aliases for the given denom
116    pub aliases: Vec<String>,
117}
118
119impl TryFrom<ProtoDenomUnit> for DenomUnit {
120    type Error = ChainError;
121
122    fn try_from(du: ProtoDenomUnit) -> Result<Self, Self::Error> {
123        Ok(Self {
124            denom: du.denom.parse()?,
125            exponent: du.exponent,
126            aliases: du.aliases,
127        })
128    }
129}
130
131impl From<DenomUnit> for ProtoDenomUnit {
132    fn from(du: DenomUnit) -> Self {
133        Self {
134            denom: du.denom.into(),
135            exponent: du.exponent,
136            aliases: du.aliases,
137        }
138    }
139}
140
141#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq, Hash)]
142pub struct ParamsResponse {
143    pub params: Option<Params>,
144}
145
146#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq, Hash)]
147pub struct Params {
148    pub send_enabled: Vec<SendEnabled>,
149    pub default_send_enabled: bool,
150}
151
152impl TryFrom<ProtoParams> for Params {
153    type Error = ChainError;
154
155    fn try_from(p: ProtoParams) -> Result<Self, Self::Error> {
156        Ok(Self {
157            send_enabled: p
158                .send_enabled
159                .into_iter()
160                .map(TryInto::try_into)
161                .collect::<Result<Vec<_>, _>>()?,
162            default_send_enabled: p.default_send_enabled,
163        })
164    }
165}
166
167impl From<Params> for ProtoParams {
168    fn from(p: Params) -> Self {
169        Self {
170            send_enabled: p.send_enabled.into_iter().map(Into::into).collect(),
171            default_send_enabled: p.default_send_enabled,
172        }
173    }
174}
175
176/// SendEnabled maps coin denom to a send_enabled status (whether a denom is sendable).
177#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq, Hash)]
178pub struct SendEnabled {
179    pub denom: Denom,
180    pub enabled: bool,
181}
182
183impl TryFrom<ProtoSendEnabled> for SendEnabled {
184    type Error = ChainError;
185
186    fn try_from(se: ProtoSendEnabled) -> Result<Self, Self::Error> {
187        Ok(Self {
188            denom: se.denom.parse()?,
189            enabled: se.enabled,
190        })
191    }
192}
193
194impl From<SendEnabled> for ProtoSendEnabled {
195    fn from(se: SendEnabled) -> Self {
196        Self {
197            denom: se.denom.into(),
198            enabled: se.enabled,
199        }
200    }
201}
202
203#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
204pub struct SendRequest {
205    pub from: Address,
206    pub to: Address,
207    pub amounts: Vec<Coin>,
208}
209
210pub type SendRequestProto = SendRequest;
211
212impl fmt::Display for SendRequest {
213    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214        write!(f, "{} sends ", self.from)?;
215
216        for a in &self.amounts {
217            write!(f, "{a} ")?;
218        }
219
220        write!(f, "-> {}", self.to)
221    }
222}
223
224impl Msg for SendRequestProto {
225    type Proto = MsgSend;
226    type Err = BankError;
227}
228
229impl TryFrom<MsgSend> for SendRequest {
230    type Error = BankError;
231
232    fn try_from(msg: MsgSend) -> Result<Self, Self::Error> {
233        Ok(Self {
234            from: msg.from_address.parse()?,
235            to: msg.to_address.parse()?,
236            amounts: msg
237                .amount
238                .into_iter()
239                .map(TryFrom::try_from)
240                .collect::<Result<Vec<_>, _>>()?,
241        })
242    }
243}
244
245impl TryFrom<SendRequest> for MsgSend {
246    type Error = BankError;
247
248    fn try_from(req: SendRequest) -> Result<Self, Self::Error> {
249        if req.amounts.is_empty() {
250            return Err(BankError::EmptyAmount);
251        }
252
253        for amount in &req.amounts {
254            if amount.amount == 0 {
255                return Err(BankError::EmptyAmount);
256            }
257        }
258
259        Ok(Self {
260            from_address: req.from.into(),
261            to_address: req.to.into(),
262            amount: req.amounts.into_iter().map(Into::into).collect(),
263        })
264    }
265}
266
267// #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
268// pub struct SendResponse {
269//     pub res: ChainTxResponse,
270// }