1#![allow(clippy::field_reassign_with_default)] use hermit_toolkit_permit::Permit;
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7use cosmwasm_std::{Binary, HumanAddr, StdError, StdResult, Uint128};
8
9use crate::batch;
10use crate::transaction_history::{RichTx, Tx};
11use crate::viewing_key::ViewingKey;
12
13#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
14pub struct InitHook {
15 pub msg: Binary,
16 pub contract_addr: HumanAddr,
17 pub code_hash: String,
18}
19
20#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema)]
21pub struct InitialBalance {
22 pub address: HumanAddr,
23 pub amount: Uint128,
24}
25
26#[derive(Serialize, Deserialize, JsonSchema)]
28pub struct InitMsg {
29 pub name: String,
30 pub admin: Option<HumanAddr>,
31 pub symbol: String,
32 pub decimals: u8,
33 pub initial_balances: Option<Vec<InitialBalance>>,
34 pub prng_seed: Binary,
35 pub config: Option<InitConfig>,
36 pub init_hook: Option<InitHook>,
37}
38
39impl InitMsg {
40 pub fn config(&self) -> InitConfig {
41 self.config.clone().unwrap_or_default()
42 }
43}
44
45#[derive(Serialize, Deserialize, JsonSchema, Clone, Default, Debug)]
47#[serde(rename_all = "snake_case")]
48pub struct InitConfig {
49 public_total_supply: Option<bool>,
50 enable_deposit: Option<bool>,
51 enable_redeem: Option<bool>,
52 enable_mint: Option<bool>,
53 enable_burn: Option<bool>,
54}
55
56impl InitConfig {
57 pub fn public_total_supply(&self) -> bool {
58 self.public_total_supply.unwrap_or(false)
59 }
60
61 pub fn deposit_enabled(&self) -> bool {
62 self.enable_deposit.unwrap_or(false)
63 }
64
65 pub fn redeem_enabled(&self) -> bool {
66 self.enable_redeem.unwrap_or(false)
67 }
68
69 pub fn mint_enabled(&self) -> bool {
70 self.enable_mint.unwrap_or(false)
71 }
72
73 pub fn burn_enabled(&self) -> bool {
74 self.enable_burn.unwrap_or(false)
75 }
76}
77
78#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug)]
82#[serde(rename_all = "snake_case")]
83pub enum HandleMsg {
84 Redeem {
85 amount: Uint128,
86 denom: Option<String>,
87 padding: Option<String>,
88 },
89 Deposit {
90 padding: Option<String>,
91 },
92
93 Transfer {
95 recipient: HumanAddr,
96 amount: Uint128,
97 memo: Option<String>,
98 padding: Option<String>,
99 },
100 Send {
101 recipient: HumanAddr,
102 recipient_code_hash: Option<String>,
103 amount: Uint128,
104 msg: Option<Binary>,
105 memo: Option<String>,
106 padding: Option<String>,
107 },
108 BatchTransfer {
109 actions: Vec<batch::TransferAction>,
110 padding: Option<String>,
111 },
112 BatchSend {
113 actions: Vec<batch::SendAction>,
114 padding: Option<String>,
115 },
116 Burn {
117 amount: Uint128,
118 memo: Option<String>,
119 padding: Option<String>,
120 },
121 RegisterReceive {
122 code_hash: String,
123 padding: Option<String>,
124 },
125 CreateViewingKey {
126 entropy: String,
127 padding: Option<String>,
128 },
129 SetViewingKey {
130 key: String,
131 padding: Option<String>,
132 },
133
134 IncreaseAllowance {
136 spender: HumanAddr,
137 amount: Uint128,
138 expiration: Option<u64>,
139 padding: Option<String>,
140 },
141 DecreaseAllowance {
142 spender: HumanAddr,
143 amount: Uint128,
144 expiration: Option<u64>,
145 padding: Option<String>,
146 },
147 TransferFrom {
148 owner: HumanAddr,
149 recipient: HumanAddr,
150 amount: Uint128,
151 memo: Option<String>,
152 padding: Option<String>,
153 },
154 SendFrom {
155 owner: HumanAddr,
156 recipient: HumanAddr,
157 recipient_code_hash: Option<String>,
158 amount: Uint128,
159 msg: Option<Binary>,
160 memo: Option<String>,
161 padding: Option<String>,
162 },
163 BatchTransferFrom {
164 actions: Vec<batch::TransferFromAction>,
165 padding: Option<String>,
166 },
167 BatchSendFrom {
168 actions: Vec<batch::SendFromAction>,
169 padding: Option<String>,
170 },
171 BurnFrom {
172 owner: HumanAddr,
173 amount: Uint128,
174 memo: Option<String>,
175 padding: Option<String>,
176 },
177 BatchBurnFrom {
178 actions: Vec<batch::BurnFromAction>,
179 padding: Option<String>,
180 },
181
182 Mint {
184 recipient: HumanAddr,
185 amount: Uint128,
186 memo: Option<String>,
187 padding: Option<String>,
188 },
189 BatchMint {
190 actions: Vec<batch::MintAction>,
191 padding: Option<String>,
192 },
193 AddMinters {
194 minters: Vec<HumanAddr>,
195 padding: Option<String>,
196 },
197 RemoveMinters {
198 minters: Vec<HumanAddr>,
199 padding: Option<String>,
200 },
201 SetMinters {
202 minters: Vec<HumanAddr>,
203 padding: Option<String>,
204 },
205
206 ChangeAdmin {
208 address: HumanAddr,
209 padding: Option<String>,
210 },
211 SetContractStatus {
212 level: ContractStatusLevel,
213 padding: Option<String>,
214 },
215
216 RevokePermit {
218 permit_name: String,
219 padding: Option<String>,
220 },
221}
222
223#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug)]
224#[serde(rename_all = "snake_case")]
225pub enum HandleAnswer {
226 Deposit {
228 status: ResponseStatus,
229 },
230 Redeem {
231 status: ResponseStatus,
232 },
233
234 Transfer {
236 status: ResponseStatus,
237 },
238 Send {
239 status: ResponseStatus,
240 },
241 BatchTransfer {
242 status: ResponseStatus,
243 },
244 BatchSend {
245 status: ResponseStatus,
246 },
247 Burn {
248 status: ResponseStatus,
249 },
250 RegisterReceive {
251 status: ResponseStatus,
252 },
253 CreateViewingKey {
254 key: ViewingKey,
255 },
256 SetViewingKey {
257 status: ResponseStatus,
258 },
259
260 IncreaseAllowance {
262 spender: HumanAddr,
263 owner: HumanAddr,
264 allowance: Uint128,
265 },
266 DecreaseAllowance {
267 spender: HumanAddr,
268 owner: HumanAddr,
269 allowance: Uint128,
270 },
271 TransferFrom {
272 status: ResponseStatus,
273 },
274 SendFrom {
275 status: ResponseStatus,
276 },
277 BatchTransferFrom {
278 status: ResponseStatus,
279 },
280 BatchSendFrom {
281 status: ResponseStatus,
282 },
283 BurnFrom {
284 status: ResponseStatus,
285 },
286 BatchBurnFrom {
287 status: ResponseStatus,
288 },
289
290 Mint {
292 status: ResponseStatus,
293 },
294 BatchMint {
295 status: ResponseStatus,
296 },
297 AddMinters {
298 status: ResponseStatus,
299 },
300 RemoveMinters {
301 status: ResponseStatus,
302 },
303 SetMinters {
304 status: ResponseStatus,
305 },
306
307 ChangeAdmin {
309 status: ResponseStatus,
310 },
311 SetContractStatus {
312 status: ResponseStatus,
313 },
314
315 RevokePermit {
317 status: ResponseStatus,
318 },
319}
320
321#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
325#[serde(rename_all = "snake_case")]
326pub enum QueryMsg {
327 TokenInfo {},
328 TokenConfig {},
329 ContractStatus {},
330 ExchangeRate {},
331 Allowance {
332 owner: HumanAddr,
333 spender: HumanAddr,
334 key: String,
335 },
336 Balance {
337 address: HumanAddr,
338 key: String,
339 },
340 TransferHistory {
341 address: HumanAddr,
342 key: String,
343 page: Option<u32>,
344 page_size: u32,
345 },
346 TransactionHistory {
347 address: HumanAddr,
348 key: String,
349 page: Option<u32>,
350 page_size: u32,
351 },
352 Minters {},
353 WithPermit {
354 permit: Permit,
355 query: QueryWithPermit,
356 },
357}
358
359impl QueryMsg {
360 pub fn get_validation_params(&self) -> (Vec<&HumanAddr>, ViewingKey) {
361 match self {
362 Self::Balance { address, key } => (vec![address], ViewingKey(key.clone())),
363 Self::TransferHistory { address, key, .. } => (vec![address], ViewingKey(key.clone())),
364 Self::TransactionHistory { address, key, .. } => {
365 (vec![address], ViewingKey(key.clone()))
366 }
367 Self::Allowance {
368 owner,
369 spender,
370 key,
371 ..
372 } => (vec![owner, spender], ViewingKey(key.clone())),
373 _ => panic!("This query type does not require authentication"),
374 }
375 }
376}
377
378#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
382#[serde(rename_all = "snake_case")]
383pub enum QueryWithPermit {
384 Allowance {
385 owner: HumanAddr,
386 spender: HumanAddr,
387 },
388 Balance {},
389 TransferHistory {
390 page: Option<u32>,
391 page_size: u32,
392 },
393 TransactionHistory {
394 page: Option<u32>,
395 page_size: u32,
396 },
397}
398
399#[derive(Serialize, Deserialize, JsonSchema, Debug)]
400#[serde(rename_all = "snake_case")]
401pub enum QueryAnswer {
402 TokenInfo {
403 name: String,
404 symbol: String,
405 decimals: u8,
406 total_supply: Option<Uint128>,
407 },
408 TokenConfig {
409 public_total_supply: bool,
410 deposit_enabled: bool,
411 redeem_enabled: bool,
412 mint_enabled: bool,
413 burn_enabled: bool,
414 },
415 ContractStatus {
416 status: ContractStatusLevel,
417 },
418 ExchangeRate {
419 rate: Uint128,
420 denom: String,
421 },
422 Allowance {
423 spender: HumanAddr,
424 owner: HumanAddr,
425 allowance: Uint128,
426 expiration: Option<u64>,
427 },
428 Balance {
429 amount: Uint128,
430 },
431 TransferHistory {
432 txs: Vec<Tx>,
433 total: Option<u64>,
434 },
435 TransactionHistory {
436 txs: Vec<RichTx>,
437 total: Option<u64>,
438 },
439 ViewingKeyError {
440 msg: String,
441 },
442 Minters {
443 minters: Vec<HumanAddr>,
444 },
445}
446
447#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema)]
448pub struct CreateViewingKeyResponse {
449 pub key: String,
450}
451
452#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
453#[serde(rename_all = "snake_case")]
454pub enum ResponseStatus {
455 Success,
456 Failure,
457}
458
459#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
460#[serde(rename_all = "snake_case")]
461pub enum ContractStatusLevel {
462 NormalRun,
463 StopAllButRedeems,
464 StopAll,
465}
466
467pub fn status_level_to_u8(status_level: ContractStatusLevel) -> u8 {
468 match status_level {
469 ContractStatusLevel::NormalRun => 0,
470 ContractStatusLevel::StopAllButRedeems => 1,
471 ContractStatusLevel::StopAll => 2,
472 }
473}
474
475pub fn u8_to_status_level(status_level: u8) -> StdResult<ContractStatusLevel> {
476 match status_level {
477 0 => Ok(ContractStatusLevel::NormalRun),
478 1 => Ok(ContractStatusLevel::StopAllButRedeems),
479 2 => Ok(ContractStatusLevel::StopAll),
480 _ => Err(StdError::generic_err("Invalid state level")),
481 }
482}
483
484pub fn space_pad(block_size: usize, message: &mut Vec<u8>) -> &mut Vec<u8> {
486 let len = message.len();
487 let surplus = len % block_size;
488 if surplus == 0 {
489 return message;
490 }
491
492 let missing = block_size - surplus;
493 message.reserve(missing);
494 message.extend(std::iter::repeat(b' ').take(missing));
495 message
496}
497
498#[cfg(test)]
499mod tests {
500 use super::*;
501 use cosmwasm_std::{from_slice, StdResult};
502
503 #[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq)]
504 #[serde(rename_all = "snake_case")]
505 pub enum Something {
506 Var { padding: Option<String> },
507 }
508
509 #[test]
510 fn test_deserialization_of_missing_option_fields() -> StdResult<()> {
511 let input = b"{ \"var\": {} }";
512 let obj: Something = from_slice(input)?;
513 assert_eq!(
514 obj,
515 Something::Var { padding: None },
516 "unexpected value: {:?}",
517 obj
518 );
519 Ok(())
520 }
521}