1use cosmwasm_std::{Addr, Api, BlockInfo, CanonicalAddr, ContractInfo, Empty, Env, MemoryStorage, OwnedDeps, Querier, RecoverPubkeyError, StdError, StdResult, Timestamp, VerificationError, Order, Storage, Uint128, Response};
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use serde_json::to_string;
5use serde_with::serde_as;
6use std::collections::HashMap;
7use std::marker::PhantomData;
8use wasm_bindgen::{JsValue, JsError};
9
10const CANONICAL_LENGTH: usize = 54;
11
12pub fn create_env() -> Env {
13 create_ownable_env(String::new(), None)
14}
15
16pub fn create_ownable_env(chain_id: impl Into<String>, time: Option<Timestamp>) -> Env {
17 Env {
18 block: BlockInfo {
19 height: 0,
20 time: time.unwrap_or_else(|| Timestamp::from_seconds(0)),
21 chain_id: chain_id.into(),
22 },
23 contract: ContractInfo {
24 address: Addr::unchecked(""),
25 },
26 transaction: None,
27 }
28}
29
30pub fn load_owned_deps(state_dump: Option<IdbStateDump>) -> OwnedDeps<MemoryStorage, EmptyApi, EmptyQuerier, Empty> {
31 match state_dump {
32 None => OwnedDeps {
33 storage: MemoryStorage::default(),
34 api: EmptyApi::default(),
35 querier: EmptyQuerier::default(),
36 custom_query_type: PhantomData,
37 },
38 Some(dump) => {
39 let idb_storage = IdbStorage::load(dump);
40 OwnedDeps {
41 storage: idb_storage.storage,
42 api: EmptyApi::default(),
43 querier: EmptyQuerier::default(),
44 custom_query_type: PhantomData,
45 }
46 }
47 }
48}
49
50pub fn get_random_color(hash: String) -> String {
52 let (red, green, blue) = derive_rgb_values(hash);
53 rgb_hex(red, green, blue)
54}
55
56
57pub fn derive_rgb_values(hash: String) -> (u8, u8, u8) {
59 let mut s = hash.trim().trim_start_matches("0x").to_string();
61 if s.len() % 2 == 1 {
62 s.insert(0, '0');
63 }
64
65 match hex::decode(&s) {
66 Ok(mut bytes) => {
67 bytes.reverse();
68 let r = *bytes.get(0).unwrap_or(&0);
69 let g = *bytes.get(1).unwrap_or(&0);
70 let b = *bytes.get(2).unwrap_or(&0);
71 (r, g, b)
72 }
73 Err(_) => (0, 0, 0),
74 }
75}
76
77pub fn rgb_hex(r: u8, g: u8, b: u8) -> String {
80 format!("#{:02X}{:02X}{:02X}", r, g, b)
81}
82
83pub fn get_json_response(storage: MemoryStorage, response: Response) -> Result<JsValue, JsError> {
87 let state_dump= IdbStateDump::from(storage);
88 let ownable_state = to_string(&response)?;
89 let response_map = js_sys::Map::new();
90 response_map.set(
91 &JsValue::from_str("mem"),
92 &JsValue::from(to_string(&state_dump)?)
93 );
94 response_map.set(
95 &JsValue::from_str("result"),
96 &JsValue::from(ownable_state)
97 );
98 Ok(JsValue::from(response_map))
99}
100
101pub struct IdbStorage {
102 pub storage: MemoryStorage,
103}
104
105impl IdbStorage {
106 pub fn load(idb: IdbStateDump) -> Self {
107 let mut store = IdbStorage {
108 storage: MemoryStorage::new(),
109 };
110 store.load_to_mem_storage(idb);
111 store
112 }
113
114 pub fn load_to_mem_storage(&mut self, idb_state: IdbStateDump) {
116 for (k, v) in idb_state.state_dump.into_iter() {
117 self.storage.set(&k, &v);
118 }
119 }
120}
121
122#[serde_as]
123#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
124pub struct IdbStateDump {
125 #[serde_as(as = "Vec<(_, _)>")]
127 pub state_dump: HashMap<Vec<u8>, Vec<u8>>,
128}
129
130impl IdbStateDump {
131 pub fn from(store: MemoryStorage) -> IdbStateDump {
133 let mut state: HashMap<Vec<u8>, Vec<u8>> = HashMap::new();
134
135 for (key, value) in store.range(None,None, Order::Ascending) {
136 state.insert(key, value);
137 }
138 IdbStateDump {
139 state_dump: state,
140 }
141 }
142}
143
144#[derive(Copy, Clone)]
146pub struct EmptyApi {
147 canonical_length: usize,
150}
151
152impl Default for EmptyApi {
153 fn default() -> Self {
154 EmptyApi {
155 canonical_length: CANONICAL_LENGTH,
156 }
157 }
158}
159
160impl Api for EmptyApi {
161 fn addr_validate(&self, human: &str) -> StdResult<Addr> {
162 self.addr_canonicalize(human).map(|_canonical| ())?;
163 Ok(Addr::unchecked(human))
164 }
165
166 fn addr_canonicalize(&self, human: &str) -> StdResult<CanonicalAddr> {
167 if human.len() < 3 {
169 return Err(StdError::generic_err(
170 "Invalid input: human address too short",
171 ));
172 }
173 if human.len() > self.canonical_length {
174 return Err(StdError::generic_err(
175 "Invalid input: human address too long",
176 ));
177 }
178
179 let mut out = Vec::from(human);
180
181 out.resize(self.canonical_length, 0x00);
183 Ok(out.into())
191 }
192
193 fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr> {
194 if canonical.len() != self.canonical_length {
195 return Err(StdError::generic_err(
196 "Invalid input: canonical address length not correct",
197 ));
198 }
199
200 let tmp: Vec<u8> = canonical.clone().into();
201 let trimmed = tmp.into_iter().filter(|&x| x != 0x00).collect();
210 let human = String::from_utf8(trimmed)?;
212 Ok(Addr::unchecked(human))
213 }
214
215 fn secp256k1_verify(
216 &self,
217 _message_hash: &[u8],
218 _signature: &[u8],
219 _public_key: &[u8],
220 ) -> Result<bool, VerificationError> {
221 Err(VerificationError::unknown_err(0))
222 }
223
224 fn secp256k1_recover_pubkey(
225 &self,
226 _message_hash: &[u8],
227 _signature: &[u8],
228 _recovery_param: u8,
229 ) -> Result<Vec<u8>, RecoverPubkeyError> {
230 Err(RecoverPubkeyError::unknown_err(0))
231 }
232
233 fn ed25519_verify(
234 &self,
235 _message: &[u8],
236 _signature: &[u8],
237 _public_key: &[u8],
238 ) -> Result<bool, VerificationError> {
239 Ok(true)
240 }
241
242 fn ed25519_batch_verify(
243 &self,
244 _messages: &[&[u8]],
245 _signatures: &[&[u8]],
246 _public_keys: &[&[u8]],
247 ) -> Result<bool, VerificationError> {
248 Ok(true)
249 }
250
251 fn debug(&self, message: &str) {
252 println!("{}", message);
253 }
254}
255
256#[derive(Default)]
258pub struct EmptyQuerier {}
259
260impl Querier for EmptyQuerier {
261 fn raw_query(&self, _bin_request: &[u8]) -> cosmwasm_std::QuerierResult {
262 todo!()
263 }
264}
265
266#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)]
268pub struct Metadata {
269 pub image: Option<String>,
270 pub image_data: Option<String>,
271 pub external_url: Option<String>,
272 pub description: Option<String>,
273 pub name: Option<String>,
274 pub background_color: Option<String>,
276 pub animation_url: Option<String>,
277 pub youtube_url: Option<String>,
278}
279
280#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
281#[serde(rename_all = "snake_case")]
282pub struct ExternalEventMsg {
283 pub network: Option<String>,
286 pub event_type: String,
287 pub attributes: HashMap<String, String>,
288}
289
290#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
291pub struct OwnableInfo {
292 pub owner: Addr,
293 pub issuer: Addr,
294 pub ownable_type: Option<String>,
295}
296
297#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
298pub struct NFT {
299 pub network: String, pub id: Uint128,
301 pub address: String, pub lock_service: Option<String>,
303}
304
305#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
306pub struct InfoResponse {
307 pub owner: Addr,
308 pub issuer: Addr,
309 pub nft: Option<NFT>,
310 pub ownable_type: Option<String>,
311}