mars_utils/
helpers.rs

1use cosmwasm_std::{coins, Addr, Api, BankMsg, CosmosMsg, Decimal, StdResult, Uint128};
2
3use crate::error::ValidationError;
4
5pub fn build_send_asset_msg(recipient_addr: &Addr, denom: &str, amount: Uint128) -> CosmosMsg {
6    CosmosMsg::Bank(BankMsg::Send {
7        to_address: recipient_addr.into(),
8        amount: coins(amount.u128(), denom),
9    })
10}
11
12/// Used when unwrapping an optional address sent in a contract call by a user.
13/// Validates addreess if present, otherwise uses a given default value.
14pub fn option_string_to_addr(
15    api: &dyn Api,
16    option_string: Option<String>,
17    default: Addr,
18) -> StdResult<Addr> {
19    match option_string {
20        Some(input_addr) => api.addr_validate(&input_addr),
21        None => Ok(default),
22    }
23}
24
25pub fn decimal_param_lt_one(param_value: Decimal, param_name: &str) -> Result<(), ValidationError> {
26    if !param_value.lt(&Decimal::one()) {
27        Err(ValidationError::InvalidParam {
28            param_name: param_name.to_string(),
29            invalid_value: param_value.to_string(),
30            predicate: "< 1".to_string(),
31        })
32    } else {
33        Ok(())
34    }
35}
36
37pub fn decimal_param_le_one(param_value: Decimal, param_name: &str) -> Result<(), ValidationError> {
38    if !param_value.le(&Decimal::one()) {
39        Err(ValidationError::InvalidParam {
40            param_name: param_name.to_string(),
41            invalid_value: param_value.to_string(),
42            predicate: "<= 1".to_string(),
43        })
44    } else {
45        Ok(())
46    }
47}
48
49pub fn integer_param_gt_zero(param_value: u64, param_name: &str) -> Result<(), ValidationError> {
50    if !param_value.gt(&0) {
51        Err(ValidationError::InvalidParam {
52            param_name: param_name.to_string(),
53            invalid_value: param_value.to_string(),
54            predicate: "> 0".to_string(),
55        })
56    } else {
57        Ok(())
58    }
59}
60
61pub fn zero_address() -> Addr {
62    Addr::unchecked("")
63}
64
65/// follows cosmos SDK validation logic where denoms can be 3 - 128 characters long
66/// and starts with a letter, followed but either a letter, number, or separator ( ‘/' , ‘:' , ‘.’ , ‘_’ , or '-')
67/// reference: https://github.com/cosmos/cosmos-sdk/blob/7728516abfab950dc7a9120caad4870f1f962df5/types/coin.go#L865-L867
68pub fn validate_native_denom(denom: &str) -> Result<(), ValidationError> {
69    if denom.len() < 3 || denom.len() > 128 {
70        return Err(ValidationError::InvalidDenom {
71            reason: "Invalid denom length".to_string(),
72        });
73    }
74
75    let mut chars = denom.chars();
76    let first = chars.next().unwrap();
77    if !first.is_ascii_alphabetic() {
78        return Err(ValidationError::InvalidDenom {
79            reason: "First character is not ASCII alphabetic".to_string(),
80        });
81    }
82
83    let set = ['/', ':', '.', '_', '-'];
84    for c in chars {
85        if !(c.is_ascii_alphanumeric() || set.contains(&c)) {
86            return Err(ValidationError::InvalidDenom {
87                reason: "Not all characters are ASCII alphanumeric or one of:  /  :  .  _  -"
88                    .to_string(),
89            });
90        }
91    }
92
93    Ok(())
94}