1use cosmwasm_schema::QueryResponses;
9use cosmwasm_std::{Binary, StdError, StdResult, Uint128};
10#[allow(unused)]
11use cw20::{
12 AllAccountsResponse, AllAllowancesResponse, AllowanceResponse, BalanceResponse,
13 DownloadLogoResponse, MarketingInfoResponse, TokenInfoResponse,
14};
15pub use cw20::{Cw20Coin, Cw20ExecuteMsg, Expiration, Logo, MinterResponse};
16pub use cw20_base::msg::QueryMsg as Cw20QueryMsg;
17use std::convert::TryInto;
18
19#[cosmwasm_schema::cw_serde]
23pub struct InstantiateMsg {
24 pub name: String,
26 pub symbol: String,
28 pub decimals: u8,
30 pub initial_balances: Vec<Cw20Coin>,
32 pub mint: Option<MinterResponse>,
34 pub version_control_address: String,
36}
37
38#[cosmwasm_schema::cw_serde]
42pub struct MigrateMsg {}
43
44impl InstantiateMsg {
45 pub fn get_cap(&self) -> Option<Uint128> {
46 self.mint.as_ref().and_then(|v| v.cap)
47 }
48
49 pub fn validate(&self) -> StdResult<()> {
50 if !is_valid_name(&self.name) {
52 return Err(StdError::generic_err(
53 "Name is not in the expected format (3-50 UTF-8 bytes)",
54 ));
55 }
56 if !is_valid_symbol(&self.symbol) {
57 return Err(StdError::generic_err(
58 "Ticker symbol is not in expected format [a-zA-Z\\-]{3,12}",
59 ));
60 }
61 if self.decimals > 18 {
62 return Err(StdError::generic_err("Decimals must not exceed 18"));
63 }
64 Ok(())
65 }
66}
67
68fn is_valid_name(name: &str) -> bool {
73 let bytes = name.as_bytes();
74 if bytes.len() < 3 || bytes.len() > 50 {
75 return false;
76 }
77 true
78}
79
80fn is_valid_symbol(symbol: &str) -> bool {
85 let bytes = symbol.as_bytes();
86 if bytes.len() < 3 || bytes.len() > 12 {
87 return false;
88 }
89 for byte in bytes.iter() {
90 if (*byte != 45) && (*byte < 65 || *byte > 90) && (*byte < 97 || *byte > 122) {
91 return false;
92 }
93 }
94 true
95}
96
97#[cosmwasm_schema::cw_serde]
98#[cfg_attr(feature = "boot", derive(boot_core::ExecuteFns))]
99pub enum ExecuteMsg {
100 UpdateWhitelist {
101 to_add: Vec<String>,
102 to_remove: Vec<String>,
103 restrict_transfers: Option<bool>,
104 },
105 UpdateAdmin {
106 new_admin: String,
107 },
108 Transfer {
110 recipient: String,
111 amount: Uint128,
112 },
113 Burn {
115 amount: Uint128,
116 },
117 Send {
120 contract: String,
121 amount: Uint128,
122 msg: Binary,
123 },
124 IncreaseAllowance {
128 spender: String,
129 amount: Uint128,
130 expires: Option<Expiration>,
131 },
132 DecreaseAllowance {
136 spender: String,
137 amount: Uint128,
138 expires: Option<Expiration>,
139 },
140 TransferFrom {
143 owner: String,
144 recipient: String,
145 amount: Uint128,
146 },
147 SendFrom {
150 owner: String,
151 contract: String,
152 amount: Uint128,
153 msg: Binary,
154 },
155 BurnFrom {
157 owner: String,
158 amount: Uint128,
159 },
160 Mint {
163 recipient: String,
164 amount: Uint128,
165 },
166 UpdateMarketing {
170 project: Option<String>,
172 description: Option<String>,
174 marketing: Option<String>,
176 },
177 UploadLogo(Logo),
179}
180
181impl TryInto<Cw20ExecuteMsg> for ExecuteMsg {
182 type Error = StdError;
183
184 fn try_into(self) -> Result<Cw20ExecuteMsg, Self::Error> {
185 match self {
186 ExecuteMsg::UpdateWhitelist {
187 to_add: _,
188 to_remove: _,
189 restrict_transfers: _,
190 } => Err(StdError::generic_err("can't parse into cw20 msg")),
191 ExecuteMsg::UpdateAdmin { new_admin: _ } => {
192 Err(StdError::generic_err("can't parse into cw20 msg"))
193 }
194 ExecuteMsg::Transfer { recipient, amount } => {
195 Ok(Cw20ExecuteMsg::Transfer { recipient, amount })
196 }
197 ExecuteMsg::Burn { amount } => Ok(Cw20ExecuteMsg::Burn { amount }),
198 ExecuteMsg::Send {
199 contract,
200 amount,
201 msg,
202 } => Ok(Cw20ExecuteMsg::Send {
203 contract,
204 amount,
205 msg,
206 }),
207 ExecuteMsg::IncreaseAllowance {
208 spender,
209 amount,
210 expires,
211 } => Ok(Cw20ExecuteMsg::IncreaseAllowance {
212 spender,
213 amount,
214 expires,
215 }),
216 ExecuteMsg::DecreaseAllowance {
217 spender,
218 amount,
219 expires,
220 } => Ok(Cw20ExecuteMsg::DecreaseAllowance {
221 spender,
222 amount,
223 expires,
224 }),
225 ExecuteMsg::TransferFrom {
226 owner,
227 recipient,
228 amount,
229 } => Ok(Cw20ExecuteMsg::TransferFrom {
230 owner,
231 recipient,
232 amount,
233 }),
234 ExecuteMsg::SendFrom {
235 owner,
236 contract,
237 amount,
238 msg,
239 } => Ok(Cw20ExecuteMsg::SendFrom {
240 owner,
241 contract,
242 amount,
243 msg,
244 }),
245 ExecuteMsg::BurnFrom { owner, amount } => {
246 Ok(Cw20ExecuteMsg::BurnFrom { owner, amount })
247 }
248 ExecuteMsg::Mint { recipient, amount } => {
249 Ok(Cw20ExecuteMsg::Mint { recipient, amount })
250 }
251 ExecuteMsg::UpdateMarketing {
252 project,
253 description,
254 marketing,
255 } => Ok(Cw20ExecuteMsg::UpdateMarketing {
256 project,
257 description,
258 marketing,
259 }),
260 ExecuteMsg::UploadLogo(l) => Ok(Cw20ExecuteMsg::UploadLogo(l)),
261 }
262 }
263}
264#[cosmwasm_schema::cw_serde]
265#[derive(QueryResponses)]
266#[cfg_attr(feature = "boot", derive(boot_core::QueryFns))]
267pub enum QueryMsg {
268 #[returns(ConfigResponse)]
269 Config {},
270 #[returns(BalanceResponse)]
273 Balance { address: String },
274 #[returns(TokenInfoResponse)]
277 TokenInfo {},
278 #[returns(MinterResponse)]
282 Minter {},
283 #[returns(AllowanceResponse)]
287 Allowance { owner: String, spender: String },
288 #[returns(AllAllowancesResponse)]
292 AllAllowances {
293 owner: String,
294 start_after: Option<String>,
295 limit: Option<u32>,
296 },
297 #[returns(AllAccountsResponse)]
301 AllAccounts {
302 start_after: Option<String>,
303 limit: Option<u32>,
304 },
305 #[returns(MarketingInfoResponse)]
310 MarketingInfo {},
311 #[returns(DownloadLogoResponse)]
316 DownloadLogo {},
317}
318
319impl TryInto<Cw20QueryMsg> for QueryMsg {
320 type Error = StdError;
321
322 fn try_into(self) -> Result<Cw20QueryMsg, Self::Error> {
323 match self {
324 Self::Balance { address } => Ok(Cw20QueryMsg::Balance { address }),
325 Self::TokenInfo {} => Ok(Cw20QueryMsg::TokenInfo {}),
326 Self::Minter {} => Ok(Cw20QueryMsg::Minter {}),
327 Self::Allowance { owner, spender } => Ok(Cw20QueryMsg::Allowance { owner, spender }),
328 Self::AllAllowances {
329 owner,
330 start_after,
331 limit,
332 } => Ok(Cw20QueryMsg::AllAllowances {
333 owner,
334 start_after,
335 limit,
336 }),
337 Self::AllAccounts { start_after, limit } => {
338 Ok(Cw20QueryMsg::AllAccounts { start_after, limit })
339 }
340 Self::MarketingInfo {} => Ok(Cw20QueryMsg::MarketingInfo {}),
341 Self::DownloadLogo {} => Ok(Cw20QueryMsg::DownloadLogo {}),
342 QueryMsg::Config {} => Err(StdError::generic_err("could not convert into cw20 query")),
343 }
344 }
345}
346#[cosmwasm_schema::cw_serde]
347pub struct ConfigResponse {
348 pub transfers_restricted: bool,
349 pub version_control_address: String,
350 pub whitelisted_addr: Vec<String>,
351 pub admin: String,
352}