cyber_std/tokenfactory/
msg.rs

1use crate::tokenfactory::types::Metadata;
2use cosmwasm_schema::cw_serde;
3use cosmwasm_std::{Binary, CosmosMsg, CustomMsg, StdResult, Uint128};
4
5/// Special messages to be supported by any chain that supports token_factory
6#[cw_serde]
7pub enum TokenFactoryMsg {
8    /// CreateDenom creates a new factory denom, of denomination:
9    /// factory/{creating contract bech32 address}/{Subdenom}
10    /// Subdenom can be of length at most 44 characters, in [0-9a-zA-Z./]
11    /// Empty subdenoms are valid.
12    /// The (creating contract address, subdenom) pair must be unique.
13    /// The created denom's admin is the creating contract address,
14    /// but this admin can be changed using the UpdateAdmin binding.
15    ///
16    /// If you set an initial metadata here, this is equivalent
17    /// to calling SetMetadata directly on the returned denom.
18    CreateDenom {
19        subdenom: String,
20        // TODO investigate if this is interoperable with Osmosis
21        metadata: Option<Metadata>,
22    },
23    /// ChangeAdmin changes the admin for a factory denom.
24    /// Can only be called by the current contract admin.
25    /// If the NewAdminAddress is empty, the denom will have no admin.
26    ChangeAdmin {
27        denom: String,
28        new_admin_address: String,
29    },
30    /// Contracts can mint native tokens for an existing factory denom
31    /// that they are the admin of.
32    MintTokens {
33        denom: String,
34        amount: Uint128,
35        mint_to_address: String,
36    },
37    /// Contracts can burn native tokens for an existing factory denom
38    /// tshat they are the admin of.
39    BurnTokens {
40        denom: String,
41        amount: Uint128,
42        burn_from_address: String,
43    },
44    /// Contracts can force transfer tokens for an existing factory denom
45    /// that they are the admin of.
46    ForceTransfer {
47        denom: String,
48        amount: Uint128,
49        from_address: String,
50        to_address: String,
51    },
52    SetMetadata {
53        denom: String,
54        metadata: Metadata,
55    },
56}
57
58/// This is in the data field in the reply from a TokenFactoryMsg::CreateDenom SubMsg
59/// Custom code to parse from protobuf with minimal wasm bytecode bloat
60pub struct CreateDenomResponse {
61    pub new_token_denom: String,
62}
63
64impl CreateDenomResponse {
65    /// Call this to process data field from the SubMsg data field
66    pub fn from_reply_data(data: Binary) -> StdResult<Self> {
67        // Manual protobuf decoding
68        let mut data = Vec::from(data);
69        // Parse contract addr
70        let new_token_denom = copied_from_cw_utils::parse_protobuf_string(&mut data, 1)?;
71        Ok(CreateDenomResponse { new_token_denom })
72    }
73
74    pub fn encode(&self) -> StdResult<Binary> {
75        // TODO
76        Ok(b"".into())
77    }
78}
79
80// FIXME: just import cw_utils::parse_protobuf_string when it is exported
81mod copied_from_cw_utils {
82    use cosmwasm_std::{StdError, StdResult};
83
84    // Protobuf wire types (https://developers.google.com/protocol-buffers/docs/encoding)
85    const WIRE_TYPE_LENGTH_DELIMITED: u8 = 2;
86    // Up to 9 bytes of varints as a practical limit (https://github.com/multiformats/unsigned-varint#practical-maximum-of-9-bytes-for-security)
87    const VARINT_MAX_BYTES: usize = 9;
88
89    pub fn parse_protobuf_string(data: &mut Vec<u8>, field_number: u8) -> StdResult<String> {
90        let str_field = parse_protobuf_length_prefixed(data, field_number)?;
91        Ok(String::from_utf8(str_field)?)
92    }
93
94    /// Helper function to parse length-prefixed protobuf fields.
95    /// The remaining of the data is kept in the data parameter.
96    fn parse_protobuf_length_prefixed(data: &mut Vec<u8>, field_number: u8) -> StdResult<Vec<u8>> {
97        if data.is_empty() {
98            return Ok(vec![]);
99        };
100        let mut rest_1 = data.split_off(1);
101        let wire_type = data[0] & 0b11;
102        let field = data[0] >> 3;
103
104        if field != field_number {
105            return Err(StdError::parse_err(
106                "length_prefix_field",
107                format!(
108                    "failed to decode Protobuf message: invalid field #{} for field #{}",
109                    field, field_number
110                ),
111            ));
112        }
113        if wire_type != WIRE_TYPE_LENGTH_DELIMITED {
114            return Err(StdError::parse_err(
115                "length_prefix_field",
116                format!(
117                    "failed to decode Protobuf message: field #{}: invalid wire type {}",
118                    field_number, wire_type
119                ),
120            ));
121        }
122
123        let len = parse_protobuf_varint(&mut rest_1, field_number)?;
124        if rest_1.len() < len {
125            return Err(StdError::parse_err(
126                "length_prefix_field",
127                format!(
128                    "failed to decode Protobuf message: field #{}: message too short",
129                    field_number
130                ),
131            ));
132        }
133        *data = rest_1.split_off(len);
134
135        Ok(rest_1)
136    }
137
138    /// Base128 varint decoding.
139    /// The remaining of the data is kept in the data parameter.
140    fn parse_protobuf_varint(data: &mut Vec<u8>, field_number: u8) -> StdResult<usize> {
141        let data_len = data.len();
142        let mut len: u64 = 0;
143        let mut i = 0;
144        while i < VARINT_MAX_BYTES {
145            if data_len == i {
146                return Err(StdError::parse_err(
147                    "varint",
148                    format!(
149                        "failed to decode Protobuf message: field #{}: varint data too short",
150                        field_number
151                    ),
152                ));
153            }
154            len += ((data[i] & 0x7f) as u64) << (i * 7);
155            if data[i] & 0x80 == 0 {
156                break;
157            }
158            i += 1;
159        }
160        if i == VARINT_MAX_BYTES {
161            return Err(StdError::parse_err(
162                "varint",
163                format!(
164                    "failed to decode Protobuf message: field #{}: varint data too long",
165                    field_number
166                ),
167            ));
168        }
169        *data = data[i + 1..].to_owned();
170
171        Ok(len as usize) // Gently fall back to the arch's max addressable size
172    }
173}