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 wasm_bindgen::{JsValue, JsError};
7use std::collections::HashMap;
8use std::marker::PhantomData;
9use blake2::Blake2bVar;
10use blake2::digest::{Update, VariableOutput};
11use sha2::Digest as Sha2Digest;
12use sha3::{Digest};
13
14const CANONICAL_LENGTH: usize = 54;
15
16pub fn create_lto_env() -> Env {
17 Env {
18 block: BlockInfo {
19 height: 0,
20 time: Timestamp::from_seconds(0),
21 chain_id: "lto".to_string(),
22 },
23 contract: ContractInfo {
24 address: Addr::unchecked(""),
25 },
26 transaction: None,
27 }
28}
29
30pub fn load_lto_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}
50
51pub fn address_eip155(public_key: String) -> Result<Addr, StdError> {
55 if public_key.is_empty() {
56 return Err(StdError::not_found("empty input"));
57 }
58
59 let pk = bs58::decode(public_key.as_bytes()).into_vec();
61 let decoded_pk = match pk {
62 Ok(pk) => pk,
63 Err(e) => return Err(StdError::generic_err(e.to_string())),
64 };
65
66 let public_key = secp256k1::PublicKey::from_slice(decoded_pk.as_slice()).unwrap();
68 let mut uncompressed_hex_pk = hex::encode(public_key.serialize_uncompressed());
69 if uncompressed_hex_pk.starts_with("04") {
70 uncompressed_hex_pk = uncompressed_hex_pk.split_off(2);
71 }
72
73 let uncompressed_raw_pk = hex::decode(uncompressed_hex_pk).unwrap();
75
76 let mut hasher = sha3::Keccak256::new();
77 hasher.input(uncompressed_raw_pk.as_slice());
78 let hashed_addr = hex::encode(hasher.result().as_slice()).to_string();
79
80 let result = &hashed_addr[hashed_addr.len() - 40..];
81 let checksum_addr = "0x".to_owned() + eip_55_checksum(result).as_str();
82
83 Ok(Addr::unchecked(checksum_addr))
84}
85
86fn eip_55_checksum(addr: &str) -> String {
87 let mut checksum_hasher = sha3::Keccak256::new();
88 checksum_hasher.input(&addr[addr.len() - 40..].as_bytes());
89 let hashed_addr = hex::encode(checksum_hasher.result()).to_string();
90
91 let mut checksum_buff = "".to_owned();
92 let result_chars: Vec<char> = addr.chars()
93 .into_iter()
94 .collect();
95 let keccak_chars: Vec<char> = hashed_addr.chars()
96 .into_iter()
97 .collect();
98 for i in 0..addr.len() {
99 let mut char = result_chars[i];
100 if char.is_alphabetic() {
101 let keccak_digit = keccak_chars[i]
102 .to_digit(16)
103 .unwrap();
104 if keccak_digit >= 8 {
106 char = char.to_ascii_uppercase();
107 }
108 }
109 checksum_buff += char.to_string().as_str();
110 }
111
112 checksum_buff
113}
114
115pub fn address_lto(network_id: char, public_key: String) -> Result<Addr, StdError> {
120 if network_id != 'L' && network_id != 'T' {
121 return Err(StdError::generic_err("unrecognized network_id"));
122 }
123 if bs58::decode(public_key.clone()).into_vec().is_err() {
124 return Err(StdError::generic_err("invalid public key"));
125 }
126
127 let public_key = bs58::decode(public_key).into_vec().unwrap();
129 let network_id = network_id as u8;
131 let pub_key_secure_hash = secure_hash(public_key.as_slice());
132 let address_bytes = &pub_key_secure_hash[0..20];
134 let version = &1_u8.to_be_bytes();
135 let checksum_input:Vec<u8> = [version, &[network_id], address_bytes].concat();
136
137 let checksum = &secure_hash(checksum_input.as_slice())
139 .to_vec()[0..4];
140
141 let addr_fields = [
142 version,
143 &[network_id],
144 address_bytes,
145 checksum
146 ];
147
148 let address: Vec<u8> = addr_fields.concat();
149 Ok(Addr::unchecked(base58(address.as_slice())))
150}
151
152fn base58(input: &[u8]) -> String {
153 bs58::encode(input).into_string()
154}
155
156fn secure_hash(m: &[u8]) -> Vec<u8> {
157 let mut hasher = Blake2bVar::new(32).unwrap();
158 hasher.update(m);
159 let mut buf = [0u8; 32];
160 hasher.finalize_variable(&mut buf).unwrap();
161
162 let mut sha256_hasher = sha2::Sha256::new();
164 Update::update(&mut sha256_hasher, buf.as_slice());
165 let res = sha256_hasher.finalize();
166 res.to_vec()
170}
171
172pub fn get_random_color(hash: String) -> String {
174 let (red, green, blue) = derive_rgb_values(hash);
175 rgb_hex(red, green, blue)
176}
177
178pub fn derive_rgb_values(hash: String) -> (u8, u8, u8) {
180 let mut decoded_hash = bs58::decode(&hash).into_vec().unwrap();
181 decoded_hash.reverse();
182 (decoded_hash[0], decoded_hash[1], decoded_hash[2])
183}
184
185pub fn rgb_hex(r: u8, g: u8, b: u8) -> String {
188 format!("#{:02X}{:02X}{:02X}", r, g, b)
189}
190
191pub fn get_json_response(storage: MemoryStorage, response: Response) -> Result<JsValue, JsError> {
195 let state_dump= IdbStateDump::from(storage);
196 let ownable_state = to_string(&response)?;
197 let response_map = js_sys::Map::new();
198 response_map.set(
199 &JsValue::from_str("mem"),
200 &JsValue::from(to_string(&state_dump)?)
201 );
202 response_map.set(
203 &JsValue::from_str("result"),
204 &JsValue::from(ownable_state)
205 );
206 Ok(JsValue::from(response_map))
207}
208
209pub struct IdbStorage {
210 pub storage: MemoryStorage,
211}
212
213impl IdbStorage {
214 pub fn load(idb: IdbStateDump) -> Self {
215 let mut store = IdbStorage {
216 storage: MemoryStorage::new(),
217 };
218 store.load_to_mem_storage(idb);
219 store
220 }
221
222 pub fn load_to_mem_storage(&mut self, idb_state: IdbStateDump) {
224 for (k, v) in idb_state.state_dump.into_iter() {
225 self.storage.set(&k, &v);
226 }
227 }
228}
229
230#[serde_as]
231#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
232pub struct IdbStateDump {
233 #[serde_as(as = "Vec<(_, _)>")]
235 pub state_dump: HashMap<Vec<u8>, Vec<u8>>,
236}
237
238impl IdbStateDump {
239 pub fn from(store: MemoryStorage) -> IdbStateDump {
241 let mut state: HashMap<Vec<u8>, Vec<u8>> = HashMap::new();
242
243 for (key, value) in store.range(None,None, Order::Ascending) {
244 state.insert(key, value);
245 }
246 IdbStateDump {
247 state_dump: state,
248 }
249 }
250}
251
252#[derive(Copy, Clone)]
254pub struct EmptyApi {
255 canonical_length: usize,
258}
259
260impl Default for EmptyApi {
261 fn default() -> Self {
262 EmptyApi {
263 canonical_length: CANONICAL_LENGTH,
264 }
265 }
266}
267
268impl Api for EmptyApi {
269 fn addr_validate(&self, human: &str) -> StdResult<Addr> {
270 self.addr_canonicalize(human).map(|_canonical| ())?;
271 Ok(Addr::unchecked(human))
272 }
273
274 fn addr_canonicalize(&self, human: &str) -> StdResult<CanonicalAddr> {
275 if human.len() < 3 {
277 return Err(StdError::generic_err(
278 "Invalid input: human address too short",
279 ));
280 }
281 if human.len() > self.canonical_length {
282 return Err(StdError::generic_err(
283 "Invalid input: human address too long",
284 ));
285 }
286
287 let mut out = Vec::from(human);
288
289 out.resize(self.canonical_length, 0x00);
291 Ok(out.into())
299 }
300
301 fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr> {
302 if canonical.len() != self.canonical_length {
303 return Err(StdError::generic_err(
304 "Invalid input: canonical address length not correct",
305 ));
306 }
307
308 let tmp: Vec<u8> = canonical.clone().into();
309 let trimmed = tmp.into_iter().filter(|&x| x != 0x00).collect();
318 let human = String::from_utf8(trimmed)?;
320 Ok(Addr::unchecked(human))
321 }
322
323 fn secp256k1_verify(
324 &self,
325 _message_hash: &[u8],
326 _signature: &[u8],
327 _public_key: &[u8],
328 ) -> Result<bool, VerificationError> {
329 Err(VerificationError::unknown_err(0))
330 }
331
332 fn secp256k1_recover_pubkey(
333 &self,
334 _message_hash: &[u8],
335 _signature: &[u8],
336 _recovery_param: u8,
337 ) -> Result<Vec<u8>, RecoverPubkeyError> {
338 Err(RecoverPubkeyError::unknown_err(0))
339 }
340
341 fn ed25519_verify(
342 &self,
343 _message: &[u8],
344 _signature: &[u8],
345 _public_key: &[u8],
346 ) -> Result<bool, VerificationError> {
347 Ok(true)
348 }
349
350 fn ed25519_batch_verify(
351 &self,
352 _messages: &[&[u8]],
353 _signatures: &[&[u8]],
354 _public_keys: &[&[u8]],
355 ) -> Result<bool, VerificationError> {
356 Ok(true)
357 }
358
359 fn debug(&self, message: &str) {
360 println!("{}", message);
361 }
362}
363
364#[derive(Default)]
366pub struct EmptyQuerier {}
367
368impl Querier for EmptyQuerier {
369 fn raw_query(&self, _bin_request: &[u8]) -> cosmwasm_std::QuerierResult {
370 todo!()
371 }
372}
373
374#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)]
376pub struct Metadata {
377 pub image: Option<String>,
378 pub image_data: Option<String>,
379 pub external_url: Option<String>,
380 pub description: Option<String>,
381 pub name: Option<String>,
382 pub background_color: Option<String>,
384 pub animation_url: Option<String>,
385 pub youtube_url: Option<String>,
386}
387
388#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
389#[serde(rename_all = "snake_case")]
390pub struct ExternalEventMsg {
391 pub network: Option<String>,
394 pub event_type: String,
395 pub attributes: HashMap<String, String>,
396}
397
398#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
399pub struct OwnableInfo {
400 pub owner: Addr,
401 pub issuer: Addr,
402 pub ownable_type: Option<String>,
403}
404
405#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
406pub struct NFT {
407 pub network: String, pub id: Uint128,
409 pub address: String, pub lock_service: Option<String>,
411}
412
413#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
414pub struct InfoResponse {
415 pub owner: Addr,
416 pub issuer: Addr,
417 pub nft: Option<NFT>,
418 pub ownable_type: Option<String>,
419}