1use cosmwasm_std::{DepsMut, StdError, Uint128};
3
4use cw20::{EmbeddedLogo, Logo, LogoInfo, MarketingInfoResponse};
5
6use cw20_base::msg::InstantiateMsg;
7use cw20_base::state::{MinterData, TokenInfo, LOGO, MARKETING_INFO, TOKEN_INFO};
8use cw20_base::ContractError;
9
10pub fn instantiate_token_info_and_marketing(
11 deps: &mut DepsMut,
12 msg: InstantiateMsg,
13 total_supply: Uint128,
14) -> Result<(), ContractError> {
15 if let Some(limit) = msg.get_cap() {
16 if total_supply > limit {
17 return Err(StdError::generic_err("Initial supply greater than cap").into());
18 }
19 }
20
21 let mint = match msg.mint {
22 Some(m) => Some(MinterData {
23 minter: deps.api.addr_validate(&m.minter)?,
24 cap: m.cap,
25 }),
26 None => None,
27 };
28
29 let data = TokenInfo {
31 name: msg.name,
32 symbol: msg.symbol,
33 decimals: msg.decimals,
34 total_supply,
35 mint,
36 };
37 TOKEN_INFO.save(deps.storage, &data)?;
38
39 if let Some(marketing) = msg.marketing {
40 let logo = if let Some(logo) = marketing.logo {
41 verify_logo(&logo)?;
42 LOGO.save(deps.storage, &logo)?;
43
44 match logo {
45 Logo::Url(url) => Some(LogoInfo::Url(url)),
46 Logo::Embedded(_) => Some(LogoInfo::Embedded),
47 }
48 } else {
49 None
50 };
51
52 let data = MarketingInfoResponse {
53 project: marketing.project,
54 description: marketing.description,
55 marketing: marketing
56 .marketing
57 .map(|addr| deps.api.addr_validate(&addr))
58 .transpose()?,
59 logo,
60 };
61 MARKETING_INFO.save(deps.storage, &data)?;
62 }
63
64 Ok(())
65}
66
67const LOGO_SIZE_CAP: usize = 5 * 1024;
68
69fn verify_xml_preamble(data: &[u8]) -> Result<(), ContractError> {
71 let preamble = data
75 .split_inclusive(|c| *c == b'>')
76 .next()
77 .ok_or(ContractError::InvalidXmlPreamble {})?;
78
79 const PREFIX: &[u8] = b"<?xml ";
80 const POSTFIX: &[u8] = b"?>";
81
82 if !(preamble.starts_with(PREFIX) && preamble.ends_with(POSTFIX)) {
83 Err(ContractError::InvalidXmlPreamble {})
84 } else {
85 Ok(())
86 }
87
88 }
91
92fn verify_xml_logo(logo: &[u8]) -> Result<(), ContractError> {
94 verify_xml_preamble(logo)?;
95
96 if logo.len() > LOGO_SIZE_CAP {
97 Err(ContractError::LogoTooBig {})
98 } else {
99 Ok(())
100 }
101}
102
103fn verify_png_logo(logo: &[u8]) -> Result<(), ContractError> {
105 const HEADER: [u8; 8] = [0x89, b'P', b'N', b'G', 0x0d, 0x0a, 0x1a, 0x0a];
112 if logo.len() > LOGO_SIZE_CAP {
113 Err(ContractError::LogoTooBig {})
114 } else if !logo.starts_with(&HEADER) {
115 Err(ContractError::InvalidPngHeader {})
116 } else {
117 Ok(())
118 }
119}
120
121fn verify_logo(logo: &Logo) -> Result<(), ContractError> {
123 match logo {
124 Logo::Embedded(EmbeddedLogo::Svg(logo)) => verify_xml_logo(logo),
125 Logo::Embedded(EmbeddedLogo::Png(logo)) => verify_png_logo(logo),
126 Logo::Url(_) => Ok(()), }
128}