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
56pub fn derive_rgb_values(hash: String) -> (u8, u8, u8) {
58 let mut decoded_hash = bs58::decode(&hash).into_vec().unwrap();
59 decoded_hash.reverse();
60 (decoded_hash[0], decoded_hash[1], decoded_hash[2])
61}
62
63pub fn rgb_hex(r: u8, g: u8, b: u8) -> String {
66 format!("#{:02X}{:02X}{:02X}", r, g, b)
67}
68
69pub fn get_json_response(storage: MemoryStorage, response: Response) -> Result<JsValue, JsError> {
73 let state_dump= IdbStateDump::from(storage);
74 let ownable_state = to_string(&response)?;
75 let response_map = js_sys::Map::new();
76 response_map.set(
77 &JsValue::from_str("mem"),
78 &JsValue::from(to_string(&state_dump)?)
79 );
80 response_map.set(
81 &JsValue::from_str("result"),
82 &JsValue::from(ownable_state)
83 );
84 Ok(JsValue::from(response_map))
85}
86
87pub struct IdbStorage {
88 pub storage: MemoryStorage,
89}
90
91impl IdbStorage {
92 pub fn load(idb: IdbStateDump) -> Self {
93 let mut store = IdbStorage {
94 storage: MemoryStorage::new(),
95 };
96 store.load_to_mem_storage(idb);
97 store
98 }
99
100 pub fn load_to_mem_storage(&mut self, idb_state: IdbStateDump) {
102 for (k, v) in idb_state.state_dump.into_iter() {
103 self.storage.set(&k, &v);
104 }
105 }
106}
107
108#[serde_as]
109#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
110pub struct IdbStateDump {
111 #[serde_as(as = "Vec<(_, _)>")]
113 pub state_dump: HashMap<Vec<u8>, Vec<u8>>,
114}
115
116impl IdbStateDump {
117 pub fn from(store: MemoryStorage) -> IdbStateDump {
119 let mut state: HashMap<Vec<u8>, Vec<u8>> = HashMap::new();
120
121 for (key, value) in store.range(None,None, Order::Ascending) {
122 state.insert(key, value);
123 }
124 IdbStateDump {
125 state_dump: state,
126 }
127 }
128}
129
130#[derive(Copy, Clone)]
132pub struct EmptyApi {
133 canonical_length: usize,
136}
137
138impl Default for EmptyApi {
139 fn default() -> Self {
140 EmptyApi {
141 canonical_length: CANONICAL_LENGTH,
142 }
143 }
144}
145
146impl Api for EmptyApi {
147 fn addr_validate(&self, human: &str) -> StdResult<Addr> {
148 self.addr_canonicalize(human).map(|_canonical| ())?;
149 Ok(Addr::unchecked(human))
150 }
151
152 fn addr_canonicalize(&self, human: &str) -> StdResult<CanonicalAddr> {
153 if human.len() < 3 {
155 return Err(StdError::generic_err(
156 "Invalid input: human address too short",
157 ));
158 }
159 if human.len() > self.canonical_length {
160 return Err(StdError::generic_err(
161 "Invalid input: human address too long",
162 ));
163 }
164
165 let mut out = Vec::from(human);
166
167 out.resize(self.canonical_length, 0x00);
169 Ok(out.into())
177 }
178
179 fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr> {
180 if canonical.len() != self.canonical_length {
181 return Err(StdError::generic_err(
182 "Invalid input: canonical address length not correct",
183 ));
184 }
185
186 let tmp: Vec<u8> = canonical.clone().into();
187 let trimmed = tmp.into_iter().filter(|&x| x != 0x00).collect();
196 let human = String::from_utf8(trimmed)?;
198 Ok(Addr::unchecked(human))
199 }
200
201 fn secp256k1_verify(
202 &self,
203 _message_hash: &[u8],
204 _signature: &[u8],
205 _public_key: &[u8],
206 ) -> Result<bool, VerificationError> {
207 Err(VerificationError::unknown_err(0))
208 }
209
210 fn secp256k1_recover_pubkey(
211 &self,
212 _message_hash: &[u8],
213 _signature: &[u8],
214 _recovery_param: u8,
215 ) -> Result<Vec<u8>, RecoverPubkeyError> {
216 Err(RecoverPubkeyError::unknown_err(0))
217 }
218
219 fn ed25519_verify(
220 &self,
221 _message: &[u8],
222 _signature: &[u8],
223 _public_key: &[u8],
224 ) -> Result<bool, VerificationError> {
225 Ok(true)
226 }
227
228 fn ed25519_batch_verify(
229 &self,
230 _messages: &[&[u8]],
231 _signatures: &[&[u8]],
232 _public_keys: &[&[u8]],
233 ) -> Result<bool, VerificationError> {
234 Ok(true)
235 }
236
237 fn debug(&self, message: &str) {
238 println!("{}", message);
239 }
240}
241
242#[derive(Default)]
244pub struct EmptyQuerier {}
245
246impl Querier for EmptyQuerier {
247 fn raw_query(&self, _bin_request: &[u8]) -> cosmwasm_std::QuerierResult {
248 todo!()
249 }
250}
251
252#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)]
254pub struct Metadata {
255 pub image: Option<String>,
256 pub image_data: Option<String>,
257 pub external_url: Option<String>,
258 pub description: Option<String>,
259 pub name: Option<String>,
260 pub background_color: Option<String>,
262 pub animation_url: Option<String>,
263 pub youtube_url: Option<String>,
264}
265
266#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
267#[serde(rename_all = "snake_case")]
268pub struct ExternalEventMsg {
269 pub network: Option<String>,
272 pub event_type: String,
273 pub attributes: HashMap<String, String>,
274}
275
276#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
277pub struct OwnableInfo {
278 pub owner: Addr,
279 pub issuer: Addr,
280 pub ownable_type: Option<String>,
281}
282
283#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
284pub struct NFT {
285 pub network: String, pub id: Uint128,
287 pub address: String, pub lock_service: Option<String>,
289}
290
291#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
292pub struct InfoResponse {
293 pub owner: Addr,
294 pub issuer: Addr,
295 pub nft: Option<NFT>,
296 pub ownable_type: Option<String>,
297}