white_whale_std/pool_network/
token.rs

1use cosmwasm_schema::cw_serde;
2use cosmwasm_std::{StdError, StdResult, Uint128};
3use cw20::{Cw20Coin, MinterResponse};
4
5/// TokenContract InstantiateMsg
6#[cw_serde]
7pub struct InstantiateMsg {
8    pub name: String,
9    pub symbol: String,
10    pub decimals: u8,
11    pub initial_balances: Vec<Cw20Coin>,
12    pub mint: Option<MinterResponse>,
13}
14
15impl InstantiateMsg {
16    pub fn get_cap(&self) -> Option<Uint128> {
17        self.mint.as_ref().and_then(|v| v.cap)
18    }
19
20    pub fn validate(&self) -> StdResult<()> {
21        // Check name, symbol, decimals
22        if !is_valid_name(&self.name) {
23            return Err(StdError::generic_err(
24                "Name is not in the expected format (3-50 UTF-8 bytes)",
25            ));
26        }
27        if !is_valid_symbol(&self.symbol) {
28            return Err(StdError::generic_err(
29                "Ticker symbol is not in expected format [a-zA-Z\\-]{3,12}",
30            ));
31        }
32        if self.decimals > 18 {
33            return Err(StdError::generic_err("Decimals must not exceed 18"));
34        }
35        Ok(())
36    }
37}
38
39fn is_valid_name(name: &str) -> bool {
40    let bytes = name.as_bytes();
41    if bytes.len() < 3 || bytes.len() > 50 {
42        return false;
43    }
44    true
45}
46
47fn is_valid_symbol(symbol: &str) -> bool {
48    let bytes = symbol.as_bytes();
49    if bytes.len() < 3 || bytes.len() > 12 {
50        return false;
51    }
52    for byte in bytes.iter() {
53        if (*byte != 45) && (*byte < 65 || *byte > 90) && (*byte < 97 || *byte > 122) {
54            return false;
55        }
56    }
57    true
58}
59
60#[cfg(test)]
61mod test {
62    use super::*;
63
64    #[test]
65    fn get_cap() {
66        let msg = InstantiateMsg {
67            decimals: 6u8,
68            initial_balances: vec![],
69            mint: Some(MinterResponse {
70                cap: Some(Uint128::from(1u128)),
71                minter: "minter0000".to_string(),
72            }),
73            name: "test_token".to_string(),
74            symbol: "TNT".to_string(),
75        };
76
77        assert_eq!(msg.get_cap(), Some(Uint128::from(1u128)))
78    }
79
80    #[test]
81    fn validate() {
82        let valid_msg = InstantiateMsg {
83            decimals: 6u8,
84            initial_balances: vec![],
85            mint: Some(MinterResponse {
86                cap: Some(Uint128::from(1u128)),
87                minter: "minter0000".to_string(),
88            }),
89            name: "test_token".to_string(),
90            symbol: "TNT".to_string(),
91        };
92
93        assert_eq!(valid_msg.validate(), Ok(()));
94
95        let name_invalid_msg = InstantiateMsg {
96            decimals: 6u8,
97            initial_balances: vec![],
98            mint: Some(MinterResponse {
99                cap: Some(Uint128::from(1u128)),
100                minter: "minter0000".to_string(),
101            }),
102            name: "a".to_string(),
103            symbol: "TNT".to_string(),
104        };
105
106        assert_eq!(
107            name_invalid_msg.validate(),
108            Err(StdError::generic_err(
109                "Name is not in the expected format (3-50 UTF-8 bytes)",
110            ))
111        );
112
113        let symbol_invalid_msg = InstantiateMsg {
114            decimals: 6u8,
115            initial_balances: vec![],
116            mint: Some(MinterResponse {
117                cap: Some(Uint128::from(1u128)),
118                minter: "minter0000".to_string(),
119            }),
120            name: "test_token".to_string(),
121            symbol: "TN".to_string(),
122        };
123
124        assert_eq!(
125            symbol_invalid_msg.validate(),
126            Err(StdError::generic_err(
127                "Ticker symbol is not in expected format [a-zA-Z\\-]{3,12}",
128            ))
129        );
130
131        let decimal_invalid_msg = InstantiateMsg {
132            decimals: 20u8,
133            initial_balances: vec![],
134            mint: Some(MinterResponse {
135                cap: Some(Uint128::from(1u128)),
136                minter: "minter0000".to_string(),
137            }),
138            name: "test_token".to_string(),
139            symbol: "TNT".to_string(),
140        };
141
142        assert_eq!(
143            decimal_invalid_msg.validate(),
144            Err(StdError::generic_err("Decimals must not exceed 18"))
145        );
146    }
147}