From 665495d0423f3780d30be5a5a7ecf6378385ca09 Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Wed, 28 Jun 2023 17:24:38 -0300 Subject: [PATCH 01/15] feat: add carbonado header information --- .env | 3 +- Cargo.lock | 72 ++++----------------------------- Cargo.toml | 2 +- docker-compose.yml | 26 +++++++++--- docker/bitmask/Dockerfile.ST120 | 40 ++++++++++++++++++ src/bin/bitmaskd.rs | 2 +- src/carbonado.rs | 45 ++++++++++++++++----- src/constants.rs | 4 ++ src/rgb/carbonado.rs | 4 +- src/structs.rs | 7 ++++ 10 files changed, 119 insertions(+), 86 deletions(-) create mode 100644 docker/bitmask/Dockerfile.ST120 diff --git a/.env b/.env index a8bb02a5..1b5e58d5 100644 --- a/.env +++ b/.env @@ -17,7 +17,8 @@ BITCOIN_EXPLORER_API_REGTEST=http://localhost:3000/regtest/api # BITCOIN_ELECTRUM_API_SIGNET=mempool.space:60601 LNDHUB_ENDPOINT=https://lndhubx.bitmask.app # CARBONADO_ENDPOINT=https://qvijq4x0ei.execute-api.us-east-2.amazonaws.com/dev/carbonado -CARBONADO_ENDPOINT=http://localhost:7070/carbonado +BITMASK_ENDPOINT=http://localhost:7070 +CARBONADO_ENDPOINT=http://localhost:7071/carbonado BITCOIN_NETWORK=regtest STRESS_TEST=false diff --git a/Cargo.lock b/Cargo.lock index a3dfa0b7..dc7e1b27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -242,17 +242,6 @@ dependencies = [ "critical-section", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -603,7 +592,7 @@ dependencies = [ "payjoin", "percent-encoding", "postcard 1.0.4", - "pretty_env_logger 0.5.0", + "pretty_env_logger", "psbt", "regex", "reqwest", @@ -769,9 +758,9 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "carbonado" -version = "0.3.0-rc.13" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2510ef3454410abef0be2d8da5b38227530a7ea55c69f666f0179410c61f8858" +checksum = "b1da1a8984d0f5b6dc0f52fce094b537c3f004248992ac1ab829d3f36059a071" dependencies = [ "anyhow", "bao", @@ -782,7 +771,7 @@ dependencies = [ "hex", "log", "nom", - "pretty_env_logger 0.4.0", + "pretty_env_logger", "secp256k1 0.27.0", "serde", "snap", @@ -1166,26 +1155,13 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime 1.3.0", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ - "humantime 2.1.0", + "humantime", "is-terminal", "log", "regex", @@ -1583,15 +1559,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.2.6" @@ -1698,15 +1665,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - [[package]] name = "humantime" version = "2.1.0" @@ -2395,23 +2353,13 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "pretty_env_logger" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" -dependencies = [ - "env_logger 0.7.1", - "log", -] - [[package]] name = "pretty_env_logger" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" dependencies = [ - "env_logger 0.10.0", + "env_logger", "log", ] @@ -2441,12 +2389,6 @@ dependencies = [ "serde_with", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.28" @@ -2571,7 +2513,7 @@ dependencies = [ "bitcoin 0.30.0", "bp-core", "commit_verify", - "env_logger 0.10.0", + "env_logger", "log", "rgb-persist-fs", "rgb-std", diff --git a/Cargo.toml b/Cargo.toml index 09a143af..dd1e15c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ bp-core = "0.10.4" commit_verify = "0.10.3" bp-seals = "0.10.4" indexmap = "1.9.3" -carbonado = "0.3.0-rc.13" +carbonado = "0.3.1" console_error_panic_hook = "0.1.7" # directories = "4.0.1" miniscript_crate = { package = "miniscript", version = "9.0.1", features = [ diff --git a/docker-compose.yml b/docker-compose.yml index 60a7c227..d28db0de 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,10 +3,6 @@ version: "3.7" networks: bmnet: driver: bridge - # ipam: - # config: - # - subnet: 172.21.0.0/24 - # gateway: 172.21.0.1 volumes: node1_data: @@ -34,11 +30,11 @@ services: bitmaskd: container_name: bitmaskd - image: bitmask/server:latest + image: bitmask/node:latest platform: linux/amd64 build: context: ./ - dockerfile: ./docker/bitmask/Dockerfile + dockerfile: ./docker/bitmask/Dockerfile.ST120 restart: unless-stopped environment: - BITCOIN_NETWORK=regtest @@ -49,3 +45,21 @@ services: bmnet: aliases: - bitmaskd + + carbonado: + container_name: carbonado + image: carbonado/node:latest + platform: linux/amd64 + build: + context: ./ + dockerfile: ./docker/bitmask/Dockerfile + restart: unless-stopped + environment: + - BITCOIN_NETWORK=regtest + - BITCOIN_EXPLORER_API_REGTEST=http://node1:80/regtest/api + ports: + - 7071:7070 + networks: + bmnet: + aliases: + - bitmaskd diff --git a/docker/bitmask/Dockerfile.ST120 b/docker/bitmask/Dockerfile.ST120 new file mode 100644 index 00000000..72c4f1d7 --- /dev/null +++ b/docker/bitmask/Dockerfile.ST120 @@ -0,0 +1,40 @@ +# Builder +FROM rust:slim AS builder +ARG BUILDER_DIR=/srv/bitmask +ARG BUILDER_SRC=/opt/src/bitmask +ARG SOURCE_CODE=https://github.com/crisdut/bitmask-core.git +ARG VERSION=c18cba0375dbc4c2f2a5a4fe56401bf3d6d52ce7 + +RUN apt-get update -y && \ + apt-get install -y pkg-config make g++ libssl-dev git + +WORKDIR $BUILDER_DIR +WORKDIR $BUILDER_SRC +RUN git clone $SOURCE_CODE $BUILDER_SRC +RUN git checkout $VERSION +RUN cargo install --locked --features server --path . --root ${BUILDER_DIR} + +# Runtime +FROM rust:slim AS runtime + +ARG BUILDER_DIR=/srv/bitmask +ARG BIN_DIR=/usr/local/bin +ARG DATA_DIR=/tmp/bitmaskd/carbonado/ +ARG USER=bitmask + +RUN apt-get update -y && apt-get install -y iputils-ping telnet \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +RUN adduser --home "${DATA_DIR}" --shell /bin/bash --disabled-login \ + --gecos "${USER} user" ${USER} + +COPY --from=builder --chown=${USER}:${USER} \ + "${BUILDER_DIR}/bin/" "${BIN_DIR}" + +USER ${USER} +VOLUME ${DATA_DIR} +EXPOSE 7070 + +WORKDIR ${BIN_DIR} + +ENTRYPOINT ["bitmaskd"] diff --git a/src/bin/bitmaskd.rs b/src/bin/bitmaskd.rs index 054d9cc5..fcc8b884 100644 --- a/src/bin/bitmaskd.rs +++ b/src/bin/bitmaskd.rs @@ -16,7 +16,7 @@ use axum::{ use bitcoin_30::secp256k1::{ecdh::SharedSecret, PublicKey, SecretKey}; use bitmask_core::{ bitcoin::{decrypt_wallet, get_wallet_data, save_mnemonic, sign_psbt_file}, - carbonado::handle_file, + carbonado::{handle_file, retrieve}, constants::{get_marketplace_seed, get_network, get_udas_utxo, switch_network}, rgb::{ accept_transfer, clear_watcher as rgb_clear_watcher, create_invoice, create_psbt, diff --git a/src/carbonado.rs b/src/carbonado.rs index d1fc2b19..ec161348 100644 --- a/src/carbonado.rs +++ b/src/carbonado.rs @@ -8,11 +8,13 @@ use anyhow::Result; #[cfg(not(feature = "server"))] use anyhow::{anyhow, Context}; use bitcoin_30::secp256k1::{PublicKey, SecretKey}; +use carbonado::file::Header; #[cfg(not(feature = "server"))] use percent_encoding::utf8_percent_encode; pub mod constants; +use crate::structs::FileMetadata; #[cfg(not(feature = "server"))] use crate::{ carbonado::constants::FORM, @@ -27,7 +29,7 @@ pub async fn store(sk: &str, name: &str, input: &[u8]) -> Result<()> { let public_key = PublicKey::from_secret_key_global(&secret_key); let pk = public_key.serialize(); let pk_hex = hex::encode(pk); - let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level)?; + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, None)?; let endpoint = CARBONADO_ENDPOINT.read().await.to_string(); let name = utf8_percent_encode(name, FORM); let network = NETWORK.read().await.to_string(); @@ -65,13 +67,25 @@ pub async fn store(sk: &str, name: &str, input: &[u8]) -> Result<()> { let public_key = PublicKey::from_secret_key_global(&secret_key); let pk = public_key.serialize(); let pk_hex = hex::encode(pk); - let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level)?; + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, None)?; let filepath = handle_file(&pk_hex, name, body.len()).await?; fs::write(filepath, body).await?; Ok(()) } +#[cfg(not(feature = "server"))] +pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { + let mut result = FileMetadata::default(); + let (header, _) = retrieve(sk, name).await?; + if let Some(header) = header { + result.filename = header.file_name(); + result.metadata = header.metadata.to_string(); + } + + Ok(result) +} + #[cfg(not(feature = "server"))] pub async fn retrieve(sk: &str, name: &str) -> Result> { let sk = hex::decode(sk)?; @@ -103,17 +117,28 @@ pub async fn retrieve(sk: &str, name: &str) -> Result> { )); } - let encoded = response.bytes().await?; if encoded.is_empty() { - Ok(Vec::new()) + Ok((None, Vec::new())) } else { - let (_header, decoded) = carbonado::file::decode(&sk, &encoded)?; - Ok(decoded) + let (header, decoded) = carbonado::file::decode(&sk, &encoded)?; + Ok((Some(header), decoded)) } } #[cfg(feature = "server")] -pub async fn retrieve(sk: &str, name: &str) -> Result> { +pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { + let mut result = FileMetadata::default(); + let (header, _) = retrieve(sk, name).await?; + if let Some(header) = header { + result.filename = header.file_name(); + result.metadata = header.metadata.to_string(); + } + + Ok(result) +} + +#[cfg(feature = "server")] +pub async fn retrieve(sk: &str, name: &str) -> Result<(Option
, Vec)> { use crate::constants::NETWORK; let sk = hex::decode(sk)?; @@ -131,10 +156,10 @@ pub async fn retrieve(sk: &str, name: &str) -> Result> { let bytes = fs::read(filepath).await?; if bytes.is_empty() { - Ok(Vec::new()) + Ok((None, Vec::new())) } else { - let (_header, decoded) = carbonado::file::decode(&sk, &bytes)?; - Ok(decoded) + let (header, decoded) = carbonado::file::decode(&sk, &bytes)?; + Ok((Some(header), decoded)) } } diff --git a/src/constants.rs b/src/constants.rs index af9392b0..42532bc4 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -125,6 +125,10 @@ pub async fn switch_network(network_str: &str) -> Result<()> { pub static LNDHUB_ENDPOINT: Lazy> = Lazy::new(|| RwLock::new(dot_env("LNDHUB_ENDPOINT"))); +// bitmask node +pub static BITMASK_ENDPOINT: Lazy> = + Lazy::new(|| RwLock::new(dot_env("BITMASK_ENDPOINT"))); + // carbonado pub static CARBONADO_ENDPOINT: Lazy> = Lazy::new(|| RwLock::new(dot_env("CARBONADO_ENDPOINT"))); diff --git a/src/rgb/carbonado.rs b/src/rgb/carbonado.rs index 47d35d4f..967905fa 100644 --- a/src/rgb/carbonado.rs +++ b/src/rgb/carbonado.rs @@ -14,7 +14,7 @@ pub async fn store_stock(sk: &str, name: &str, stock: &Stock) -> Result<()> { } pub async fn retrieve_stock(sk: &str, name: &str) -> Result { - let data = retrieve(sk, name).await.unwrap_or_default(); + let (_, data) = retrieve(sk, name).await.unwrap_or_default(); if data.is_empty() { Ok(Stock::default()) } else { @@ -31,7 +31,7 @@ pub async fn store_wallets(sk: &str, name: &str, rgb_wallets: &RgbAccount) -> Re } pub async fn retrieve_wallets(sk: &str, name: &str) -> Result { - let data = retrieve(sk, name).await.unwrap_or_default(); + let (_, data) = retrieve(sk, name).await.unwrap_or_default(); if data.is_empty() { Ok(RgbAccount::default()) } else { diff --git a/src/structs.rs b/src/structs.rs index 2bc14a85..4d2a8721 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -640,3 +640,10 @@ pub struct ExportRequestMini { /// ContractId of the asset to export FROM the node pub asset: String, } + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct FileMetadata { + pub filename: String, + pub metadata: String, +} From 24034aaba2341df715447c75aa42719e1239df93 Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Thu, 29 Jun 2023 02:30:42 -0300 Subject: [PATCH 02/15] feat: add support to re-issue --- docker-compose.yml | 1 + docker/bitmask/Dockerfile | 4 +- docker/bitmask/Dockerfile.ST120 | 7 +- src/bin/bitmaskd.rs | 45 +++++++++-- src/carbonado.rs | 27 +++++-- src/rgb.rs | 128 +++++++++++++++++++++++++++----- src/rgb/carbonado.rs | 6 +- src/rgb/constants.rs | 2 + src/rgb/contract.rs | 4 +- src/structs.rs | 22 +++++- src/web.rs | 31 ++++++-- tests/rgb.rs | 4 + tests/rgb/sre/st130.rs | 124 +++++++++++++++++++++++++++++++ 13 files changed, 354 insertions(+), 51 deletions(-) create mode 100644 tests/rgb/sre/st130.rs diff --git a/docker-compose.yml b/docker-compose.yml index d28db0de..488f2c6f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,6 +28,7 @@ services: aliases: - node1 + # Bitmaskd 0.6.0-rc.2 bitmaskd: container_name: bitmaskd image: bitmask/node:latest diff --git a/docker/bitmask/Dockerfile b/docker/bitmask/Dockerfile index 5915369d..8837718b 100644 --- a/docker/bitmask/Dockerfile +++ b/docker/bitmask/Dockerfile @@ -1,5 +1,5 @@ # Builder -FROM rust:slim AS builder +FROM rust:slim-buster AS builder ARG BUILDER_DIR=/srv/bitmask ARG BUILDER_SRC=/opt/src/bitmask @@ -13,7 +13,7 @@ COPY . . RUN cargo install --locked --features server --path . --root ${BUILDER_DIR} # Runtime -FROM rust:slim AS runtime +FROM rust:slim-buster AS runtime ARG BUILDER_DIR=/srv/bitmask ARG BIN_DIR=/usr/local/bin diff --git a/docker/bitmask/Dockerfile.ST120 b/docker/bitmask/Dockerfile.ST120 index 72c4f1d7..2649e5e7 100644 --- a/docker/bitmask/Dockerfile.ST120 +++ b/docker/bitmask/Dockerfile.ST120 @@ -1,8 +1,8 @@ # Builder -FROM rust:slim AS builder +FROM rust:slim-buster AS builder ARG BUILDER_DIR=/srv/bitmask ARG BUILDER_SRC=/opt/src/bitmask -ARG SOURCE_CODE=https://github.com/crisdut/bitmask-core.git +ARG SOURCE_CODE=https://github.com/diba-io/bitmask-core.git ARG VERSION=c18cba0375dbc4c2f2a5a4fe56401bf3d6d52ce7 RUN apt-get update -y && \ @@ -15,7 +15,7 @@ RUN git checkout $VERSION RUN cargo install --locked --features server --path . --root ${BUILDER_DIR} # Runtime -FROM rust:slim AS runtime +FROM rust:slim-buster AS runtime ARG BUILDER_DIR=/srv/bitmask ARG BIN_DIR=/usr/local/bin @@ -36,5 +36,4 @@ VOLUME ${DATA_DIR} EXPOSE 7070 WORKDIR ${BIN_DIR} - ENTRYPOINT ["bitmaskd"] diff --git a/src/bin/bitmaskd.rs b/src/bin/bitmaskd.rs index fcc8b884..3268f987 100644 --- a/src/bin/bitmaskd.rs +++ b/src/bin/bitmaskd.rs @@ -3,6 +3,7 @@ #![cfg(not(target_arch = "wasm32"))] use std::{env, fs::OpenOptions, io::ErrorKind, net::SocketAddr, str::FromStr}; +use amplify::hex::ToHex; use anyhow::Result; use axum::{ body::Bytes, @@ -16,18 +17,19 @@ use axum::{ use bitcoin_30::secp256k1::{ecdh::SharedSecret, PublicKey, SecretKey}; use bitmask_core::{ bitcoin::{decrypt_wallet, get_wallet_data, save_mnemonic, sign_psbt_file}, - carbonado::{handle_file, retrieve}, + carbonado::{handle_file, retrieve, retrieve_metadata}, constants::{get_marketplace_seed, get_network, get_udas_utxo, switch_network}, rgb::{ accept_transfer, clear_watcher as rgb_clear_watcher, create_invoice, create_psbt, create_watcher, import as rgb_import, issue_contract, list_contracts, list_interfaces, - list_schemas, transfer_asset, watcher_address, watcher_details as rgb_watcher_details, - watcher_next_address, watcher_next_utxo, watcher_utxo, + list_schemas, reissue_contract, transfer_asset, watcher_address, + watcher_details as rgb_watcher_details, watcher_next_address, watcher_next_utxo, + watcher_utxo, }, structs::{ AcceptRequest, ImportRequest, InvoiceRequest, IssueAssetRequest, IssueRequest, MediaInfo, - PsbtRequest, RgbTransferRequest, SecretString, SelfIssueRequest, SignPsbtRequest, - WatcherRequest, + PsbtRequest, ReIssueRequest, RgbTransferRequest, SecretString, SelfIssueRequest, + SignPsbtRequest, WatcherRequest, }, }; use carbonado::file; @@ -37,11 +39,25 @@ use serde::{Deserialize, Serialize}; use tokio::fs; use tower_http::cors::CorsLayer; -async fn issue(Json(issue): Json) -> Result { - info!("POST /issue {issue:?}"); +async fn issue( + TypedHeader(auth): TypedHeader>, + Json(request): Json, +) -> Result { + info!("POST /issue {request:?}"); - let issue_res = issue_contract(&issue.sk, issue.request).await?; + let nostr_hex_sk = auth.token(); + let issue_res = issue_contract(nostr_hex_sk, request).await?; + Ok((StatusCode::OK, Json(issue_res))) +} + +async fn reissue( + TypedHeader(auth): TypedHeader>, + Json(request): Json, +) -> Result { + info!("POST /reissue {request:?}"); + let nostr_hex_sk = auth.token(); + let issue_res = reissue_contract(&nostr_hex_sk, request).await?; Ok((StatusCode::OK, Json(issue_res))) } @@ -352,6 +368,17 @@ async fn co_retrieve( } } +async fn co_metadata( + Path((pk, name)): Path<(String, String)>, +) -> Result { + info!("GET /carbonado/{pk}/{name}/metadata"); + + let metadata = retrieve_metadata(&pk, &name).await?; + let metadata = metadata.metadata.to_hex(); + debug!("file with metadata: {0}", metadata); + Ok((StatusCode::OK, Json(metadata))) +} + async fn status() -> Result { let cc = CacheControl::new().with_no_cache(); @@ -380,6 +407,7 @@ async fn main() -> Result<()> { let app = Router::new() .route("/issue", post(issue)) + .route("/reissue", post(reissue)) .route("/selfissue", post(self_issue)) .route("/invoice", post(invoice)) // .route("/psbt", post(psbt)) @@ -405,6 +433,7 @@ async fn main() -> Result<()> { .route("/carbonado/status", get(status)) .route("/carbonado/:pk/:name", post(co_store)) .route("/carbonado/:pk/:name", get(co_retrieve)) + .route("/carbonado/:pk/:name/metadata", get(co_metadata)) .layer(CorsLayer::permissive()); let network = get_network().await; diff --git a/src/carbonado.rs b/src/carbonado.rs index ec161348..4d5f563d 100644 --- a/src/carbonado.rs +++ b/src/carbonado.rs @@ -22,14 +22,20 @@ use crate::{ }; #[cfg(not(feature = "server"))] -pub async fn store(sk: &str, name: &str, input: &[u8]) -> Result<()> { +pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option>) -> Result<()> { let level = 15; let sk = hex::decode(sk)?; let secret_key = SecretKey::from_slice(&sk)?; let public_key = PublicKey::from_secret_key_global(&secret_key); let pk = public_key.serialize(); let pk_hex = hex::encode(pk); - let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, None)?; + + let mut meta: Option<[u8; 8]> = None; + if let Some(metadata) = metadata { + meta = Some(metadata.try_into().expect("invalid metadata size")); + } + + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, meta)?; let endpoint = CARBONADO_ENDPOINT.read().await.to_string(); let name = utf8_percent_encode(name, FORM); let network = NETWORK.read().await.to_string(); @@ -60,14 +66,20 @@ pub async fn store(sk: &str, name: &str, input: &[u8]) -> Result<()> { } #[cfg(feature = "server")] -pub async fn store(sk: &str, name: &str, input: &[u8]) -> Result<()> { +pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option>) -> Result<()> { let level = 15; let sk = hex::decode(sk)?; let secret_key = SecretKey::from_slice(&sk)?; let public_key = PublicKey::from_secret_key_global(&secret_key); let pk = public_key.serialize(); let pk_hex = hex::encode(pk); - let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, None)?; + + let mut meta: Option<[u8; 8]> = None; + if let Some(metadata) = metadata { + meta = Some(metadata.try_into().expect("invalid metadata size")); + } + + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, meta)?; let filepath = handle_file(&pk_hex, name, body.len()).await?; fs::write(filepath, body).await?; @@ -80,14 +92,14 @@ pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { let (header, _) = retrieve(sk, name).await?; if let Some(header) = header { result.filename = header.file_name(); - result.metadata = header.metadata.to_string(); + result.metadata = header.metadata.unwrap_or_default(); } Ok(result) } #[cfg(not(feature = "server"))] -pub async fn retrieve(sk: &str, name: &str) -> Result> { +pub async fn retrieve(sk: &str, name: &str) -> Result<(Option
, Vec)> { let sk = hex::decode(sk)?; let secret_key = SecretKey::from_slice(&sk)?; let public_key = PublicKey::from_secret_key_global(&secret_key); @@ -117,6 +129,7 @@ pub async fn retrieve(sk: &str, name: &str) -> Result> { )); } + let encoded = response.bytes().await?; if encoded.is_empty() { Ok((None, Vec::new())) } else { @@ -131,7 +144,7 @@ pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { let (header, _) = retrieve(sk, name).await?; if let Some(header) = header { result.filename = header.file_name(); - result.metadata = header.metadata.to_string(); + result.metadata = header.metadata.unwrap_or_default(); } Ok(result) diff --git a/src/rgb.rs b/src/rgb.rs index 4af13767..0d076e13 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -1,5 +1,6 @@ use std::{collections::BTreeMap, str::FromStr}; +use crate::rgb::structs::RgbAccount; use ::psbt::serialize::Serialize; use amplify::{confinement::U16, hex::ToHex}; use anyhow::{anyhow, Result}; @@ -46,12 +47,13 @@ use crate::{ wallet::list_allocations, }, structs::{ - AcceptRequest, AcceptResponse, AssetType, ContractResponse, ContractsResponse, - ImportRequest, InterfaceDetail, InterfacesResponse, InvoiceRequest, InvoiceResponse, - IssueRequest, IssueResponse, NextAddressResponse, NextUtxoResponse, NextUtxosResponse, - PsbtRequest, PsbtResponse, RgbTransferRequest, RgbTransferResponse, SchemaDetail, - SchemasResponse, WatcherDetailResponse, WatcherRequest, WatcherResponse, - WatcherUtxoResponse, + AcceptRequest, AcceptResponse, AssetType, ContractMetadata, ContractResponse, + ContractsResponse, ImportRequest, InterfaceDetail, InterfacesResponse, InvoiceRequest, + InvoiceResponse, IssueMetaRequest, IssueMetadata, IssueRequest, IssueResponse, + NewCollectible, NextAddressResponse, NextUtxoResponse, NextUtxosResponse, PsbtRequest, + PsbtResponse, ReIssueRequest, ReIssueResponse, RgbTransferRequest, RgbTransferResponse, + SchemaDetail, SchemasResponse, UDADetail, WatcherDetailResponse, WatcherRequest, + WatcherResponse, WatcherUtxoResponse, }, }; @@ -72,8 +74,107 @@ use self::{ }; /// RGB Operations -#[allow(clippy::too_many_arguments)] pub async fn issue_contract(sk: &str, request: IssueRequest) -> Result { + let mut stock = retrieve_stock(sk, ASSETS_STOCK).await?; + let mut rgb_account = retrieve_wallets(sk, ASSETS_WALLETS).await?; + + let resp = issue_rgb_contract(request, &mut stock, &mut rgb_account).await; + store_stock(sk, ASSETS_STOCK, &stock).await?; + store_wallets(sk, ASSETS_WALLETS, &rgb_account).await?; + + resp +} + +pub async fn reissue_contract(sk: &str, request: ReIssueRequest) -> Result { + let mut stock = Stock::default(); + let mut rgb_account = retrieve_wallets(sk, ASSETS_WALLETS).await?; + + let mut reissue_resp = vec![]; + for contract in request.contracts { + let ContractResponse { + ticker, + name, + description, + supply, + contract_id: _, + iimpl_id: _, + iface, + precision, + balance: _, + allocations, + contract: _, + genesis: _, + meta: contract_meta, + } = contract; + + let seals: Vec = allocations + .into_iter() + .map(|alloc| format!("tapret1st:{}", alloc.utxo)) + .collect(); + let seal = seals.first().unwrap().to_owned(); + + let mut meta = None; + if let Some(contract_meta) = contract_meta { + meta = Some(match contract_meta.meta() { + ContractMetadata::UDA(uda) => IssueMetaRequest(IssueMetadata::UDA(uda.media)), + ContractMetadata::Collectible(colectibles) => { + let mut items = vec![]; + for collectible_item in colectibles { + let UDADetail { + ticker, + name, + token_index: _, + description, + balance: _, + media, + allocations: _, + } = collectible_item; + + let new_item = NewCollectible { + ticker, + name, + description, + media, + }; + + items.push(new_item); + } + + IssueMetaRequest(IssueMetadata::Collectible(items)) + } + }) + } + + let req = IssueRequest { + ticker, + name, + description, + supply, + precision, + iface, + seal, + meta, + }; + + let resp = issue_rgb_contract(req, &mut stock, &mut rgb_account) + .await + .expect("re-issue contract failed"); + reissue_resp.push(resp); + } + + store_stock(sk, ASSETS_STOCK, &stock).await?; + store_wallets(sk, ASSETS_WALLETS, &rgb_account).await?; + + Ok(ReIssueResponse { + contracts: reissue_resp, + }) +} + +async fn issue_rgb_contract( + request: IssueRequest, + stock: &mut Stock, + rgb_account: &mut RgbAccount, +) -> Result { let IssueRequest { ticker, name, @@ -84,8 +185,6 @@ pub async fn issue_contract(sk: &str, request: IssueRequest) -> Result Result Result Result<()> { let data = stock.to_strict_serialized::()?; - - store(sk, name, &data).await + store(sk, name, &data, Some(RGB_STRICT_TYPE_VERSION.to_vec())).await } pub async fn retrieve_stock(sk: &str, name: &str) -> Result { @@ -27,7 +27,7 @@ pub async fn retrieve_stock(sk: &str, name: &str) -> Result { pub async fn store_wallets(sk: &str, name: &str, rgb_wallets: &RgbAccount) -> Result<()> { let data = to_allocvec(rgb_wallets)?; - store(sk, name, &data).await + store(sk, name, &data, Some(RGB_STRICT_TYPE_VERSION.to_vec())).await } pub async fn retrieve_wallets(sk: &str, name: &str) -> Result { diff --git a/src/rgb/constants.rs b/src/rgb/constants.rs index 43481d06..971a031b 100644 --- a/src/rgb/constants.rs +++ b/src/rgb/constants.rs @@ -2,3 +2,5 @@ pub const LIB_NAME_BITMASK: &str = "bitmask"; pub const RGB_CHANGE_INDEX: &str = "0"; pub const RGB_PSBT_TAPRET: &str = "TAPRET"; pub const RGB_DEFAULT_NAME: &str = "default"; +pub const RGB_OLDEST_VERSION: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; +pub const RGB_STRICT_TYPE_VERSION: [u8; 8] = [b'r', b'g', b'b', b's', b't', b'1', b'3', b'0']; diff --git a/src/rgb/contract.rs b/src/rgb/contract.rs index 3b35d46b..392ac22a 100644 --- a/src/rgb/contract.rs +++ b/src/rgb/contract.rs @@ -68,7 +68,7 @@ where let mut ticker = String::new(); let mut name = String::new(); - let mut precision = 0; + let mut precision: u8 = 0; let mut description = String::new(); let ty: FieldName = FieldName::from("spec"); @@ -95,7 +95,7 @@ where } if let Some(StrictVal::Enum(en)) = fields.get(&FieldName::from("precision")) { let val = en.unwrap_ord(); - precision = val as u64; + precision = val; } }; } diff --git a/src/structs.rs b/src/structs.rs index 4d2a8721..6ea968bc 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -132,6 +132,13 @@ pub struct SelfIssueRequest { pub meta: Option, } +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct ReIssueRequest { + /// previous contracts + pub contracts: Vec, +} + #[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct IssueMetaRequest(pub IssueMetadata); @@ -232,6 +239,12 @@ pub struct GenesisFormats { pub armored: String, } +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct ReIssueResponse { + pub contracts: Vec, +} + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub enum AssetType { @@ -272,7 +285,7 @@ pub struct ContractResponse { /// Amount of the asset pub supply: u64, /// Precision of the asset - pub precision: u64, + pub precision: u8, /// The user contract balance pub balance: u64, /// The contract allocations @@ -293,6 +306,10 @@ impl ContractMeta { pub fn with(metadata: ContractMetadata) -> Self { ContractMeta(metadata) } + + pub fn meta(self) -> ContractMetadata { + self.0 + } } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -536,6 +553,7 @@ pub struct AllocationDetail { /// My Allocation? pub is_mine: bool, /// Allocation spent? + #[serde(skip)] pub is_spent: bool, } @@ -645,5 +663,5 @@ pub struct ExportRequestMini { #[serde(rename_all = "camelCase")] pub struct FileMetadata { pub filename: String, - pub metadata: String, + pub metadata: [u8; 8], } diff --git a/src/web.rs b/src/web.rs index 577cb214..3913fa97 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,6 +1,6 @@ use crate::structs::{ - AcceptRequest, ImportRequest, InvoiceRequest, IssueRequest, PsbtRequest, RgbTransferRequest, - SecretString, SignPsbtRequest, WatcherRequest, + AcceptRequest, ImportRequest, InvoiceRequest, IssueRequest, PsbtRequest, ReIssueRequest, + RgbTransferRequest, SecretString, SignPsbtRequest, WatcherRequest, }; // use crate::{carbonado, lightning, rgb}; @@ -320,6 +320,22 @@ pub mod rgb { }) } + #[allow(clippy::too_many_arguments)] + #[wasm_bindgen] + pub fn reissue_contract(nostr_hex_sk: String, request: JsValue) -> Promise { + set_panic_hook(); + + future_to_promise(async move { + let req: ReIssueRequest = serde_wasm_bindgen::from_value(request).unwrap(); + match crate::rgb::reissue_contract(&nostr_hex_sk, req).await { + Ok(result) => Ok(JsValue::from_string( + serde_json::to_string(&result).unwrap(), + )), + Err(err) => Err(JsValue::from_string(err.to_string())), + } + }) + } + #[wasm_bindgen] pub fn rgb_create_invoice(nostr_hex_sk: String, request: JsValue) -> Promise { set_panic_hook(); @@ -658,11 +674,16 @@ pub mod carbonado { use super::*; #[wasm_bindgen] - pub fn store(secret_key: String, name: String, data: Vec) -> Promise { + pub fn store( + secret_key: String, + name: String, + data: Vec, + metadata: Option>, + ) -> Promise { set_panic_hook(); future_to_promise(async move { - match crate::carbonado::store(&secret_key, &name, &data).await { + match crate::carbonado::store(&secret_key, &name, &data, metadata).await { Ok(result) => Ok(JsValue::from_string( serde_json::to_string(&result).unwrap(), )), @@ -679,7 +700,7 @@ pub mod carbonado { future_to_promise(async move { match crate::carbonado::retrieve(&secret_key, &name).await { - Ok(result) => { + Ok((_, result)) => { let array = Uint8Array::new_with_length(result.len() as u32); array.copy_from(&result); Ok(JsValue::from(array)) diff --git a/tests/rgb.rs b/tests/rgb.rs index f296722b..464ffcf2 100644 --- a/tests/rgb.rs +++ b/tests/rgb.rs @@ -28,4 +28,8 @@ mod rgb { mod imports; mod std; } + + mod sre { + mod st130; + } } diff --git a/tests/rgb/sre/st130.rs b/tests/rgb/sre/st130.rs new file mode 100644 index 00000000..826d01a2 --- /dev/null +++ b/tests/rgb/sre/st130.rs @@ -0,0 +1,124 @@ +#![cfg(not(target_arch = "wasm32"))] +use crate::rgb::integration::utils::ISSUER_MNEMONIC; +use anyhow::{anyhow, Context}; +use bitmask_core::carbonado::{retrieve_metadata, store}; +use bitmask_core::structs::WatcherRequest; +use bitmask_core::{ + bitcoin::save_mnemonic, + carbonado::constants::FORM, + constants::{storage_keys::ASSETS_STOCK, BITMASK_ENDPOINT, NETWORK}, + rgb::{constants::RGB_OLDEST_VERSION, reissue_contract}, + structs::{ContractsResponse, ReIssueRequest, SecretString}, +}; +use hex::FromHex; +use nostr_sdk::key::{PublicKey, SecretKey}; +use percent_encoding::utf8_percent_encode; +use reqwest::Client; + +#[tokio::test] +#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.3.0)"] +async fn allow_re_issue_rgb_contracts() -> anyhow::Result<()> { + let bitmask_endpoint = BITMASK_ENDPOINT.read().await.to_string(); + let issuer_keys = save_mnemonic( + &SecretString(ISSUER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + + // 0. Create Watcher + let issuer_sk = &issuer_keys.private.nostr_prv; + let client = Client::new(); + let endpoint = format!("{bitmask_endpoint}/watcher"); + let watch_req = WatcherRequest { + name: "default".to_string(), + xpub: issuer_keys.public.watcher_xpub.clone(), + force: true, + }; + let resp = client + .post(&endpoint) + .json(&watch_req) + .bearer_auth(issuer_sk) + .send() + .await; + assert!(resp.is_ok()); + + // 0. Prepare Data Test + let file_name = ASSETS_STOCK.to_string(); + let input = Vec::::from_hex(STOCK_ST_120)?; + + let resp = store_in_server(issuer_sk, &file_name, &input, None).await; + assert!(resp.is_ok()); + + // 1. Retrieve metadata + let fake_file_name = "fake-name.c15"; + let resp = store(issuer_sk, &fake_file_name, &input, None).await; + assert!(resp.is_ok()); + + let resp = retrieve_metadata(issuer_sk, &fake_file_name).await; + assert!(resp.is_ok()); + + // 2. Retrieve contracts + let file_header = resp?; + if file_header.metadata == RGB_OLDEST_VERSION { + let endpoint = format!("{bitmask_endpoint}/contracts"); + + let result = client.get(&endpoint).bearer_auth(issuer_sk).send().await?; + + let resp = result.json::().await?; + let reissue_req = ReIssueRequest { + contracts: resp.contracts, + }; + + // 2. ReIssue contracts + let reissue_resp = reissue_contract(issuer_sk, reissue_req).await; + assert!(reissue_resp.is_ok()); + } + + Ok(()) +} + +async fn store_in_server( + sk: &str, + name: &str, + input: &[u8], + metadata: Option<[u8; 8]>, +) -> anyhow::Result<()> { + let level = 15; + let sk = hex::decode(sk)?; + let secret_key = SecretKey::from_slice(&sk)?; + let public_key = PublicKey::from_secret_key_global(&secret_key); + let pk = public_key.serialize(); + let pk_hex = hex::encode(pk); + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, metadata)?; + let endpoint = BITMASK_ENDPOINT.read().await.to_string(); + let name = utf8_percent_encode(name, FORM); + let network = NETWORK.read().await.to_string(); + let url = format!("{endpoint}/carbonado/{pk_hex}/{network}-{name}"); + let client = reqwest::Client::new(); + let response = client + .post(&url) + .body(body) + .header("Content-Type", "application/octet-stream") + .header("Cache-Control", "no-cache") + .send() + .await + .context(format!("Error sending JSON POST request to {url}"))?; + + let status_code = response.status().as_u16(); + + if status_code != 200 { + let response_text = response.text().await.context(format!( + "Error in parsing server response for POST JSON request to {url}" + ))?; + + println!("{}", url); + + Err(anyhow!( + "Error in storing carbonado file, status: {status_code} error: {response_text}" + )) + } else { + Ok(()) + } +} + +const STOCK_ST_120: &str = "02d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd000000030300cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e4300100d007b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100d107b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010001d007010800c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b103030001000100d00701000100d1070100010001d0070100ffff000001d007c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10001d0070100ffff01d0070100ffff0037000017acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd010b524742436f6e7472616374044e616d65050198db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d81bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0107426974636f696e0554784f757406020576616c7565cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00c7363726970745075626b65794a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba1df1d11643dd30bf0b583883dfa61289186277ace4ad075e3c67ac0b83802eaa01035374640a486578446563436170730310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e4623bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0107426974636f696e095369675363726970740501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c3027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000403719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac600040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e38fd0b174ca8528da005d978de7dd5a2a763bb67e42ca25b935edf451344229e01035374640a416c706861536d616c6c031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e00050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d104693e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100000000000000000ffff0000000000004a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba0107426974636f696e0c5363726970745075626b65790501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c52740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560107426974636f696e084f7574706f696e7406020474786964b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab404766f7574fd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d5577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b000360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377f55accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b01035374640e41736369695072696e7461626c65035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e58a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066170000445cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80600085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b0100000000000000080000000000000060fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec010b524742436f6e74726163740b41737365744e616d696e670603067469636b657292e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506046e616d6517acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd0764657461696c733719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac661cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a25510000161dac6b5168357edbd878765f0382f79d864835c01c7e3a0d0747a235404c3ba010353746408416c7068614e756d033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a66ff6ddb2093d3e48033bbd707da2588df6a93d25b7d419c0592cadb31e8a2da0107426974636f696e02547806040776657273696f6e6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e8863206696e70757473e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba076f75747075747376ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f3086c6f636b54696d656f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e886320107426974636f696e055478566572050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066176c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110000086f0cbcc3130d8fdbd168f60ebb2477f344d85659ca1fc56d84b235072b67c74501035374640e416c7068614e756d4c6f64617368033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a6f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b0107426974636f696e084c6f636b54696d650501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253175b7c2e75f4dbfc3728201bc72c62986a08f2734cb3e50f32e6aad2f21343f5a010353746409416c70686143617073031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a76ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f300081bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0000000000000000ffffffffffffffff8a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffff0000000000008df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40107426974636f696e045478496e06040a707265764f757470757452740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560973696753637269707423bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0873657175656e6365bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff7077769746e657373bd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff791281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469010b524742436f6e74726163740744657461696c730501d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f92e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506010b524742436f6e7472616374065469636b657205015cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80698db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d800085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b01000000000000002800000000000000a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffffffffffffffffa788a36d6e35c945b224869165f2844711784f55b6b484b2f21f35397170ad8401035374640255340310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fae6894c8d85e1f4b6e7a31dabf56f6a09c1f423f6ce5fd49ea56bc025cb4f22301035374640c416c7068614e756d44617368033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7ab0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a5400073027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9962000b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010b524742436f6e74726163741152696361726469616e436f6e747261637405013e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd8989010b524742436f6e747261637412446976697369626c654173736574537065630602066e616d696e6760fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec09707265636973696f6ec554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab40107426974636f696e04547869640501b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54b9ef64121db10df182d4df713abb2b2e97a73f8f9c116f81f54577c3e0bf015b010353746403446563030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80010b524742436f6e74726163740f50726f6f664f6652657365727665730602047574786fb1e43bec82e3821b2d7ccee89a7d213da8b77eea0518bcfa4f6d6f8dfe0296de0570726f6f668a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caaebbd8604f99b5c9047de07d559069a286d27c94143106e2f5eae266ae44f7168701035374640c416c706861436170734e756d0324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5abd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff70107426974636f696e075769746e6573730501f5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c548bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff70107426974636f696e055365714e6f0501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5010b524742436f6e747261637409507265636973696f6e03130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f12c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b1000000cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e430010b524742436f6e74726163740954696d657374616d70050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c752606617cb958efe9c6d304f13222e2a4907124e86e7ea1c5a74e24c3e2235f6c4d2a9a501035374640b486578446563536d616c6c0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00107426974636f696e045361747305016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b11d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100100000000000000ff00000000000000e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000004e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba00088df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40000000000000000fffffffffffffffff27e112e62134308df24f66cd6a133e473d72977d65f49467f1fd8a4d92a13c7010353746404426f6f6c03020566616c736500047472756501f41f2a6324dcada5162bb3034f7c2a19ad40b9124fb467e44c5a0d772c430d8e010353746405416c7068610334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7af5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c5480008a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe0000000000000000fffffffffffffffff82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c0107426974636f696e0b53637269707442797465730501a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fefd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d0107426974636f696e04566f75740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253100015650fb29bac1c7616f976727b1e81234887ad96e7056f5a3cc99e4a8378b31480c00035247420300d0d007000000010004d0075650fb29bac1c7616f976727b1e81234887ad96e7056f5a3cc99e4a8378b3148000001dd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce900d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bddd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce90303000763726561746564d0070473706563d107057465726d7301d0070b62656e65666963696172790001d007085472616e7366657200dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d4000000050300cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001003408b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd898901003508b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae37798610700100360806df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c01003808869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f60100013408025d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa81000c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b105030001000100340801000100350801000100360800000100380800000100013408010001000000013408c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b100013408010001000134080100010000580000017447c77d2367544618e2aaf4e680659b9df075544650b5a4bbab699ea258c800040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d651da55835280aba3b02d1b5d02fc3fc47c267e8ed85554b0e7d13beed5c132b30065602cf1069e5dcfccabc7fd98ca570ce4eb972bddfb8c63633483dd519c19d00085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b0100000000000000400000000000000006df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c0105524742323109546f6b656e44617461060805696e646578d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d7664067469636b6572d669d8d150ff6a2e7486568b066e2fb43e4efe6aab93d103d8f559d14a6ccd15046e616d65017447c77d2367544618e2aaf4e680659b9df075544650b5a4bbab699ea258c80764657461696c73181998eeb65f373753d54b4983424050c38cb464d587d6a3741a13c69abfdc1007707265766965774cc79dab63f53b172bd53af42d3c1b9e36fdc5ba19ec625dcf99cf9ee6d23178056d65646961ba7da437dd2009266764a53302be280bec57a35edea906c42185c96e1a1d4e840b6174746163686d656e74730f1b2b5d80322340d1064fcfc7b82c98002836666b576b1eb7baf1a2d2756cff0872657365727665730c90d2700887419382cbcbd28c78d7c1b112602e4438551c3ca58ae68a975cbc0718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7010552474232310949737375654d65746106010872657365727665734d09d713e21e9bbabd91ffe3ac096102dcfe3ed8994f7089158532a139a024bb09317e1367c0edbbfffb675b5329d6554a0ec62580c5e5a5215af318270a88b3010552474232310d4f776e65644672616374696f6e05016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110c90d2700887419382cbcbd28c78d7c1b112602e4438551c3ca58ae68a975cbc00040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65affcae68cd21c376584c7b4a68de738dfad6386a7d6d3a7bbb348227976d14f80f1b2b5d80322340d1064fcfc7b82c98002836666b576b1eb7baf1a2d2756cff000a0001a84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e20000000000000000140000000000000017acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd010b524742436f6e7472616374044e616d65050198db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d8181998eeb65f373753d54b4983424050c38cb464d587d6a3741a13c69abfdc1000040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65b360cb3d1a1ce2559dd5cc11d2b3164467211559b80a239b16d081f394fa5b531bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0107426974636f696e0554784f757406020576616c7565cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00c7363726970745075626b65794a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba1da55835280aba3b02d1b5d02fc3fc47c267e8ed85554b0e7d13beed5c132b3000050117acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd1df1d11643dd30bf0b583883dfa61289186277ace4ad075e3c67ac0b83802eaa01035374640a486578446563436170730310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e4623bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0107426974636f696e095369675363726970740501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c3027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000403719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac600040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e38fd0b174ca8528da005d978de7dd5a2a763bb67e42ca25b935edf451344229e01035374640a416c706861536d616c6c031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e00050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d104693e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100000000000000000ffff000000000000470ad9ae9cbc8fa7428330b0c0a4fb32d1f9fc30a94eaa4b3c41145b849a56e9000501a84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e2497c7eb9391a079a38d92afdde2e4eec03a9a37987201d5ab5b14d45c17b250d010552474232310d456e67726176696e67446174610602096170706c696564546fd3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d766407636f6e74656e747b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da24a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba0107426974636f696e0c5363726970745075626b65790501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c4cc79dab63f53b172bd53af42d3c1b9e36fdc5ba19ec625dcf99cf9ee6d2317800040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d656022af4d5e00c75978b1d60421997e0b227b395dce5e52da8e030b6ae9174a444d09d713e21e9bbabd91ffe3ac096102dcfe3ed8994f7089158532a139a024bb0009ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc800000000000000000ffff0000000000004f46dce8279430081e45f623d0d618ed7f52efb553bc241b0d2ae7ec601c1a5c01055247423231094d6564696154797065060304747970655538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa0773756274797065b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b90763686172736574b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b952740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560107426974636f696e084f7574706f696e7406020474786964b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab404766f7574fd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d5538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa010552474232310c4d656469615265674e616d650501065602cf1069e5dcfccabc7fd98ca570ce4eb972bddfb8c63633483dd519c19d5577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b000360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377f55accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b01035374640e41736369695072696e7461626c65035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e58a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066170000445cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80600085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b010000000000000008000000000000005d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa810010552474232310a416c6c6f636174696f6e0502d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d766409317e1367c0edbbfffb675b5329d6554a0ec62580c5e5a5215af318270a88b36022af4d5e00c75978b1d60421997e0b227b395dce5e52da8e030b6ae9174a440005017b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da260fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec010b524742436f6e74726163740b41737365744e616d696e670603067469636b657292e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506046e616d6517acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd0764657461696c733719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac661cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a25510000161dac6b5168357edbd878765f0382f79d864835c01c7e3a0d0747a235404c3ba010353746408416c7068614e756d033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a66ff6ddb2093d3e48033bbd707da2588df6a93d25b7d419c0592cadb31e8a2da0107426974636f696e02547806040776657273696f6e6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e8863206696e70757473e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba076f75747075747376ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f3086c6f636b54696d656f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b695eb06afff78803151c5c7c1620648f52dca30526ce3ec3fea1ad7fcab75a8a000855accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b010000000000000014000000000000006963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e886320107426974636f696e055478566572050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066176c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110000086f0cbcc3130d8fdbd168f60ebb2477f344d85659ca1fc56d84b235072b67c74501035374640e416c7068614e756d4c6f64617368033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a6f23e8a03955547d9bd76db47bb7e5eea3792d5f8f223c790cc2b5eed658c09f0005015538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa6f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b0107426974636f696e084c6f636b54696d650501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253175b7c2e75f4dbfc3728201bc72c62986a08f2734cb3e50f32e6aad2f21343f5a010353746409416c70686143617073031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a76ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f300081bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0000000000000000ffffffffffffffff7b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da2010552474232310d456d6265646465644d65646961060204747970654f46dce8279430081e45f623d0d618ed7f52efb553bc241b0d2ae7ec601c1a5c04646174618a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f6010552474232310e4174746163686d656e74547970650602026964cd2a948954a0dc1dd1a4e04145245638af3f544c133c68bf1af183cb3346668a046e616d659819b0f8b92eac0f19205791b5016c23f78f78560bb47d74e266a9c24b0cf33e8a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffff0000000000008aa05647e0f89c231194d76e4f776ef7d3255028c484cb63a8a68f7d0251695e00050192e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be8429835068df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40107426974636f696e045478496e06040a707265764f757470757452740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560973696753637269707423bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0873657175656e6365bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff7077769746e657373bd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff79048212cad2ed6e09a3e853c904f71889286e17ec23d0a3b6326ecee721b7b9901055247423231054572726f720308106672616374696f6e4f766572666c6f77010e6e6f6e457175616c56616c756573020c696e76616c696450726f6f660314696e73756666696369656e7452657365727665730415697373756545786365656473416c6c6f77616e636506126e6f6e4672616374696f6e616c546f6b656e07126e6f6e456e6772617661626c65546f6b656e0815696e76616c69644174746163686d656e74547970650991281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469010b524742436f6e74726163740744657461696c730501d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f92e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506010b524742436f6e7472616374065469636b657205015cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb8069819b0f8b92eac0f19205791b5016c23f78f78560bb47d74e266a9c24b0cf33e010552474232310e4174746163686d656e744e616d650501695eb06afff78803151c5c7c1620648f52dca30526ce3ec3fea1ad7fcab75a8a98db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d800085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b01000000000000002800000000000000a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffffffffffffffffa788a36d6e35c945b224869165f2844711784f55b6b484b2f21f35397170ad8401035374640255340310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e2010552474232310a4174746163686d656e7406020474797065869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f606646967657374b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54ae6894c8d85e1f4b6e7a31dabf56f6a09c1f423f6ce5fd49ea56bc025cb4f22301035374640c416c7068614e756d44617368033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7aaffcae68cd21c376584c7b4a68de738dfad6386a7d6d3a7bbb348227976d14f8000501ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a5400073027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9962000b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010b524742436f6e74726163741152696361726469616e436f6e747261637405013e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd8989010b524742436f6e747261637412446976697369626c654173736574537065630602066e616d696e6760fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec09707265636973696f6ec554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5b360cb3d1a1ce2559dd5cc11d2b3164467211559b80a239b16d081f394fa5b5300050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b900040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d656f23e8a03955547d9bd76db47bb7e5eea3792d5f8f223c790cc2b5eed658c09fb9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab40107426974636f696e04547869640501b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54b9ef64121db10df182d4df713abb2b2e97a73f8f9c116f81f54577c3e0bf015b010353746403446563030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80010b524742436f6e74726163740f50726f6f664f6652657365727665730602047574786fb1e43bec82e3821b2d7ccee89a7d213da8b77eea0518bcfa4f6d6f8dfe0296de0570726f6f668a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caaeba7da437dd2009266764a53302be280bec57a35edea906c42185c96e1a1d4e8400040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65470ad9ae9cbc8fa7428330b0c0a4fb32d1f9fc30a94eaa4b3c41145b849a56e9bbd8604f99b5c9047de07d559069a286d27c94143106e2f5eae266ae44f7168701035374640c416c706861436170734e756d0324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5abd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff70107426974636f696e075769746e6573730501f5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c548bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff70107426974636f696e055365714e6f0501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c1f252f38965138fc5cb730e49eda0f7f792ed6b88b2e17739d6410d251b1514010552474232310a4974656d73436f756e740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5010b524742436f6e747261637409507265636973696f6e03130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f12c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b1000000cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e430010b524742436f6e74726163740954696d657374616d70050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c752606617cb958efe9c6d304f13222e2a4907124e86e7ea1c5a74e24c3e2235f6c4d2a9a501035374640b486578446563536d616c6c0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00107426974636f696e045361747305016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b11cd2a948954a0dc1dd1a4e04145245638af3f544c133c68bf1af183cb3346668a000001d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100100000000000000ff00000000000000d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d7664010552474232310a546f6b656e496e6465780501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531d669d8d150ff6a2e7486568b066e2fb43e4efe6aab93d103d8f559d14a6ccd1500040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d658aa05647e0f89c231194d76e4f776ef7d3255028c484cb63a8a68f7d0251695ee27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000004e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba00088df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40000000000000000fffffffffffffffff27e112e62134308df24f66cd6a133e473d72977d65f49467f1fd8a4d92a13c7010353746404426f6f6c03020566616c736500047472756501f41f2a6324dcada5162bb3034f7c2a19ad40b9124fb467e44c5a0d772c430d8e010353746405416c7068610334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7af5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c5480008a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe0000000000000000fffffffffffffffff82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c0107426974636f696e0b53637269707442797465730501a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fefd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d0107426974636f696e04566f75740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000000000191da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b00dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d491da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b0403000763726561746564340804737065633508057465726d73360806746f6b656e730134080b62656e656669636961727900013408085472616e73666572000291da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b00055247423231060f6174746163686d656e74547970657301869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f60001076372656174656401cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001000a656e67726176696e677301497c7eb9391a079a38d92afdde2e4eec03a9a37987201d5ab5b14d45c17b250d0001047370656301b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100057465726d7301b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010006746f6b656e730106df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c0001030a61737365744f776e6572055d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa81000000112696e666c6174696f6e416c6c6f77616e636505c1f252f38965138fc5cb730e49eda0f7f792ed6b88b2e17739d6410d251b15140100010b75706461746552696768740101000000010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7050f6174746163686d656e745479706573000000ffff0763726561746564000100010004737065630001000100057465726d73000100010006746f6b656e73000000ffff030a61737365744f776e6572000000ffff12696e666c6174696f6e416c6c6f77616e6365000000ffff0b757064617465526967687400000001000004010304090407456e67726176650100010a656e67726176696e67730001000100010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000401020708010b62656e656669636961727905497373756501010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b702126e65774174746163686d656e745479706573010f6174746163686d656e7454797065730000ffff096e6577546f6b656e730106746f6b656e730000ffff0104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff00050103040609010b62656e65666963696172790652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff0003010207010b62656e6566696369617279009048212cad2ed6e09a3e853c904f71889286e17ec23d0a3b6326ecee721b7b9901085472616e73666572dd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce900055247423230060c6275726e6564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a0001076372656174656401cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001000c697373756564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a00010e7265706c61636564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a0001047370656301b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100057465726d7301b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae37798610700100050a61737365744f776e657202000001096275726e45706f636801010000096275726e52696768740101000112696e666c6174696f6e416c6c6f77616e6365020100010b75706461746552696768740101000000010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b704076372656174656400010001000c697373756564537570706c79000100010004737065630001000100057465726d730001000100040a61737365744f776e6572000000ffff096275726e45706f6368000000010012696e666c6174696f6e416c6c6f77616e6365000000ffff0b75706461746552696768740000000100000301030406044275726e0101f4bdcb47aa7db1caab5656f482e6788f22cf4534f93d506cdb350e13b9d0d9eb010c6275726e6564537570706c79000100010001047573656401096275726e526967687401000100010666757475726501096275726e52696768740000010000030103050005497373756501010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7010c697373756564537570706c7900010001000104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff000401030406010b62656e6566696369617279094f70656e45706f636801000001047573656401096275726e45706f63680100010002096275726e52696768740001000100046e65787401096275726e45706f636800000100000001096275726e52696768740652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265075265706c6163650101f4bdcb47aa7db1caab5656f482e6788f22cf4534f93d506cdb350e13b9d0d9eb010e7265706c61636564537570706c79000100010001047573656401096275726e526967687401000100020b62656e6566696369617279010a61737365744f776e65720000ffff0666757475726501096275726e526967687400000100000401020305010b62656e6566696369617279085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000102010b62656e65666963696172790031e4e2b06ffac24c5455a677c387081de1697ebb91ba71ef38825fc9301bc80301085472616e73666572021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f0000d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd8000000303000100040000000000d00701000c00044449424104444942410002d1070100060004004449424101d00701010003010030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f0000000022b15850d50f7ac1080500000000000000a1be14ae6fd7e13c777322802c58fd7d808f51184cfb2843bf594ffb97e790c600c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc0000dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d48000000403000100040000000000340801000c0004444942410444494241000235080100060004004449424136080100400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e6700000001340802010003013755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec74701000000393f83f1cb83ff340c0001000000010000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f00c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc000000000000000000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f03030001000000000000040000000000d007010000000000000c00044449424104444942410002d10701000000000000060004004449424100000000010000001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd00700000030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f00000000080500000000000000a1be14ae6fd7e13c777322802c58fd7d808f51184cfb2843bf594ffb97e790c6000000000000000000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bcdd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d400c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc040300010000000000000400000000003408010000000000000c000444494241044449424100023508010000000000000600040044494241360801000000000000400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e67000000000000000000000001000000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc340800003755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec747010000000c000100000001000000000000000000000000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f0000000100000030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f000000000100001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd0070000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc0000000100003755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec74701000000010000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc34080000000000000000"; From 0cd90e23215fd0eaa0e7aa7d6d19d0d504724844 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Thu, 29 Jun 2023 02:51:57 -0600 Subject: [PATCH 03/15] Refactor metadtata option type mapping. --- src/carbonado.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/carbonado.rs b/src/carbonado.rs index 4d5f563d..96da8242 100644 --- a/src/carbonado.rs +++ b/src/carbonado.rs @@ -30,10 +30,7 @@ pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option> let pk = public_key.serialize(); let pk_hex = hex::encode(pk); - let mut meta: Option<[u8; 8]> = None; - if let Some(metadata) = metadata { - meta = Some(metadata.try_into().expect("invalid metadata size")); - } + let meta: Option<[u8; 8]> = metadata.map(|m| m.try_into().expect("invalid metadata size")); let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, meta)?; let endpoint = CARBONADO_ENDPOINT.read().await.to_string(); @@ -74,10 +71,7 @@ pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option> let pk = public_key.serialize(); let pk_hex = hex::encode(pk); - let mut meta: Option<[u8; 8]> = None; - if let Some(metadata) = metadata { - meta = Some(metadata.try_into().expect("invalid metadata size")); - } + let meta: Option<[u8; 8]> = metadata.map(|m| m.try_into().expect("invalid metadata size")); let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, meta)?; From c95418825737da275096aec257bab13bf7e16a66 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Thu, 29 Jun 2023 03:09:48 -0600 Subject: [PATCH 04/15] Add linting for tests in CI. Fix web_storage test. --- .github/workflows/rust.yaml | 14 ++++++++++++-- tests/web_storage.rs | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yaml b/.github/workflows/rust.yaml index 7fff81d0..cbd3c940 100644 --- a/.github/workflows/rust.yaml +++ b/.github/workflows/rust.yaml @@ -39,9 +39,14 @@ jobs: - uses: olix0r/cargo-action-fmt/setup@v2 - uses: Swatinem/rust-cache@v2 - - name: Lint + - name: Lint src run: cargo clippy --locked --all-features --lib --message-format=json -- -D warnings | cargo-action-fmt + - name: Lint tests + run: cargo clippy --locked --all-features --tests --message-format=json -- -D warnings | cargo-action-fmt + env: + TEST_WALLET_SEED: "" + lint-wasm: runs-on: ubuntu-latest @@ -61,9 +66,14 @@ jobs: - name: Add wasm32 target run: rustup target add wasm32-unknown-unknown - - name: Lint (wasm32) + - name: Lint src (wasm32) run: cargo clippy --locked --target wasm32-unknown-unknown --lib --message-format=json -- -D warnings | cargo-action-fmt + - name: Lint tests (wasm32) + run: cargo clippy --locked --target wasm32-unknown-unknown --tests --message-format=json -- -D warnings | cargo-action-fmt + env: + TEST_WALLET_SEED: "" + test: runs-on: ubuntu-latest needs: lint diff --git a/tests/web_storage.rs b/tests/web_storage.rs index db36eace..a4e9ff15 100644 --- a/tests/web_storage.rs +++ b/tests/web_storage.rs @@ -21,7 +21,7 @@ async fn web_storage() { let data = b"Hello world!".to_vec(); info!("Testing web data store"); - resolve(store(sk.clone(), name.clone(), data.clone())).await; + resolve(store(sk.clone(), name.clone(), data.clone(), None)).await; info!("Testing web data retrieve"); let result: JsValue = resolve(retrieve(sk, name)).await; From 84982adc797eca919ba1ed8c101efdec097de30b Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Thu, 29 Jun 2023 06:10:06 -0300 Subject: [PATCH 05/15] feat: add support to re-issue --- .env | 1 + Cargo.lock | 72 ++----------------- Cargo.toml | 2 +- docker-compose.yml | 27 +++++-- docker/bitmask/Dockerfile | 4 +- docker/bitmask/Dockerfile.ST120 | 39 ++++++++++ src/bin/bitmaskd.rs | 72 ++++++++++++++++--- src/carbonado.rs | 87 ++++++++++++++++++++-- src/constants.rs | 4 ++ src/rgb.rs | 119 +++++++++++++++++++++++++++--- src/rgb/carbonado.rs | 6 +- src/rgb/constants.rs | 2 + src/rgb/contract.rs | 4 +- src/structs.rs | 27 ++++++- src/web.rs | 43 +++++++++-- tests/rgb.rs | 4 ++ tests/rgb/sre/st130.rs | 124 ++++++++++++++++++++++++++++++++ tests/web_storage.rs | 2 +- 18 files changed, 528 insertions(+), 111 deletions(-) create mode 100644 docker/bitmask/Dockerfile.ST120 create mode 100644 tests/rgb/sre/st130.rs diff --git a/.env b/.env index a8bb02a5..656b7d41 100644 --- a/.env +++ b/.env @@ -17,6 +17,7 @@ BITCOIN_EXPLORER_API_REGTEST=http://localhost:3000/regtest/api # BITCOIN_ELECTRUM_API_SIGNET=mempool.space:60601 LNDHUB_ENDPOINT=https://lndhubx.bitmask.app # CARBONADO_ENDPOINT=https://qvijq4x0ei.execute-api.us-east-2.amazonaws.com/dev/carbonado +BITMASK_ENDPOINT=http://localhost:7071 CARBONADO_ENDPOINT=http://localhost:7070/carbonado BITCOIN_NETWORK=regtest STRESS_TEST=false diff --git a/Cargo.lock b/Cargo.lock index a3dfa0b7..dc7e1b27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -242,17 +242,6 @@ dependencies = [ "critical-section", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -603,7 +592,7 @@ dependencies = [ "payjoin", "percent-encoding", "postcard 1.0.4", - "pretty_env_logger 0.5.0", + "pretty_env_logger", "psbt", "regex", "reqwest", @@ -769,9 +758,9 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "carbonado" -version = "0.3.0-rc.13" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2510ef3454410abef0be2d8da5b38227530a7ea55c69f666f0179410c61f8858" +checksum = "b1da1a8984d0f5b6dc0f52fce094b537c3f004248992ac1ab829d3f36059a071" dependencies = [ "anyhow", "bao", @@ -782,7 +771,7 @@ dependencies = [ "hex", "log", "nom", - "pretty_env_logger 0.4.0", + "pretty_env_logger", "secp256k1 0.27.0", "serde", "snap", @@ -1166,26 +1155,13 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime 1.3.0", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ - "humantime 2.1.0", + "humantime", "is-terminal", "log", "regex", @@ -1583,15 +1559,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.2.6" @@ -1698,15 +1665,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - [[package]] name = "humantime" version = "2.1.0" @@ -2395,23 +2353,13 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "pretty_env_logger" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" -dependencies = [ - "env_logger 0.7.1", - "log", -] - [[package]] name = "pretty_env_logger" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" dependencies = [ - "env_logger 0.10.0", + "env_logger", "log", ] @@ -2441,12 +2389,6 @@ dependencies = [ "serde_with", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.28" @@ -2571,7 +2513,7 @@ dependencies = [ "bitcoin 0.30.0", "bp-core", "commit_verify", - "env_logger 0.10.0", + "env_logger", "log", "rgb-persist-fs", "rgb-std", diff --git a/Cargo.toml b/Cargo.toml index 09a143af..dd1e15c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ bp-core = "0.10.4" commit_verify = "0.10.3" bp-seals = "0.10.4" indexmap = "1.9.3" -carbonado = "0.3.0-rc.13" +carbonado = "0.3.1" console_error_panic_hook = "0.1.7" # directories = "4.0.1" miniscript_crate = { package = "miniscript", version = "9.0.1", features = [ diff --git a/docker-compose.yml b/docker-compose.yml index 60a7c227..488f2c6f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,10 +3,6 @@ version: "3.7" networks: bmnet: driver: bridge - # ipam: - # config: - # - subnet: 172.21.0.0/24 - # gateway: 172.21.0.1 volumes: node1_data: @@ -32,13 +28,14 @@ services: aliases: - node1 + # Bitmaskd 0.6.0-rc.2 bitmaskd: container_name: bitmaskd - image: bitmask/server:latest + image: bitmask/node:latest platform: linux/amd64 build: context: ./ - dockerfile: ./docker/bitmask/Dockerfile + dockerfile: ./docker/bitmask/Dockerfile.ST120 restart: unless-stopped environment: - BITCOIN_NETWORK=regtest @@ -49,3 +46,21 @@ services: bmnet: aliases: - bitmaskd + + carbonado: + container_name: carbonado + image: carbonado/node:latest + platform: linux/amd64 + build: + context: ./ + dockerfile: ./docker/bitmask/Dockerfile + restart: unless-stopped + environment: + - BITCOIN_NETWORK=regtest + - BITCOIN_EXPLORER_API_REGTEST=http://node1:80/regtest/api + ports: + - 7071:7070 + networks: + bmnet: + aliases: + - bitmaskd diff --git a/docker/bitmask/Dockerfile b/docker/bitmask/Dockerfile index 5915369d..8837718b 100644 --- a/docker/bitmask/Dockerfile +++ b/docker/bitmask/Dockerfile @@ -1,5 +1,5 @@ # Builder -FROM rust:slim AS builder +FROM rust:slim-buster AS builder ARG BUILDER_DIR=/srv/bitmask ARG BUILDER_SRC=/opt/src/bitmask @@ -13,7 +13,7 @@ COPY . . RUN cargo install --locked --features server --path . --root ${BUILDER_DIR} # Runtime -FROM rust:slim AS runtime +FROM rust:slim-buster AS runtime ARG BUILDER_DIR=/srv/bitmask ARG BIN_DIR=/usr/local/bin diff --git a/docker/bitmask/Dockerfile.ST120 b/docker/bitmask/Dockerfile.ST120 new file mode 100644 index 00000000..2649e5e7 --- /dev/null +++ b/docker/bitmask/Dockerfile.ST120 @@ -0,0 +1,39 @@ +# Builder +FROM rust:slim-buster AS builder +ARG BUILDER_DIR=/srv/bitmask +ARG BUILDER_SRC=/opt/src/bitmask +ARG SOURCE_CODE=https://github.com/diba-io/bitmask-core.git +ARG VERSION=c18cba0375dbc4c2f2a5a4fe56401bf3d6d52ce7 + +RUN apt-get update -y && \ + apt-get install -y pkg-config make g++ libssl-dev git + +WORKDIR $BUILDER_DIR +WORKDIR $BUILDER_SRC +RUN git clone $SOURCE_CODE $BUILDER_SRC +RUN git checkout $VERSION +RUN cargo install --locked --features server --path . --root ${BUILDER_DIR} + +# Runtime +FROM rust:slim-buster AS runtime + +ARG BUILDER_DIR=/srv/bitmask +ARG BIN_DIR=/usr/local/bin +ARG DATA_DIR=/tmp/bitmaskd/carbonado/ +ARG USER=bitmask + +RUN apt-get update -y && apt-get install -y iputils-ping telnet \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +RUN adduser --home "${DATA_DIR}" --shell /bin/bash --disabled-login \ + --gecos "${USER} user" ${USER} + +COPY --from=builder --chown=${USER}:${USER} \ + "${BUILDER_DIR}/bin/" "${BIN_DIR}" + +USER ${USER} +VOLUME ${DATA_DIR} +EXPOSE 7070 + +WORKDIR ${BIN_DIR} +ENTRYPOINT ["bitmaskd"] diff --git a/src/bin/bitmaskd.rs b/src/bin/bitmaskd.rs index 054d9cc5..a3d31b57 100644 --- a/src/bin/bitmaskd.rs +++ b/src/bin/bitmaskd.rs @@ -3,6 +3,7 @@ #![cfg(not(target_arch = "wasm32"))] use std::{env, fs::OpenOptions, io::ErrorKind, net::SocketAddr, str::FromStr}; +use amplify::hex::ToHex; use anyhow::Result; use axum::{ body::Bytes, @@ -16,18 +17,19 @@ use axum::{ use bitcoin_30::secp256k1::{ecdh::SharedSecret, PublicKey, SecretKey}; use bitmask_core::{ bitcoin::{decrypt_wallet, get_wallet_data, save_mnemonic, sign_psbt_file}, - carbonado::handle_file, + carbonado::{handle_file, retrieve, retrieve_metadata}, constants::{get_marketplace_seed, get_network, get_udas_utxo, switch_network}, rgb::{ accept_transfer, clear_watcher as rgb_clear_watcher, create_invoice, create_psbt, create_watcher, import as rgb_import, issue_contract, list_contracts, list_interfaces, - list_schemas, transfer_asset, watcher_address, watcher_details as rgb_watcher_details, - watcher_next_address, watcher_next_utxo, watcher_utxo, + list_schemas, reissue_contract, transfer_asset, watcher_address, + watcher_details as rgb_watcher_details, watcher_next_address, watcher_next_utxo, + watcher_utxo, }, structs::{ - AcceptRequest, ImportRequest, InvoiceRequest, IssueAssetRequest, IssueRequest, MediaInfo, - PsbtRequest, RgbTransferRequest, SecretString, SelfIssueRequest, SignPsbtRequest, - WatcherRequest, + AcceptRequest, FileMetadata, ImportRequest, InvoiceRequest, IssueAssetRequest, + IssueRequest, MediaInfo, PsbtRequest, ReIssueRequest, RgbTransferRequest, SecretString, + SelfIssueRequest, SignPsbtRequest, WatcherRequest, }, }; use carbonado::file; @@ -37,11 +39,25 @@ use serde::{Deserialize, Serialize}; use tokio::fs; use tower_http::cors::CorsLayer; -async fn issue(Json(issue): Json) -> Result { - info!("POST /issue {issue:?}"); +async fn issue( + TypedHeader(auth): TypedHeader>, + Json(request): Json, +) -> Result { + info!("POST /issue {request:?}"); + + let nostr_hex_sk = auth.token(); + let issue_res = issue_contract(nostr_hex_sk, request).await?; + Ok((StatusCode::OK, Json(issue_res))) +} - let issue_res = issue_contract(&issue.sk, issue.request).await?; +async fn reissue( + TypedHeader(auth): TypedHeader>, + Json(request): Json, +) -> Result { + info!("POST /reissue {request:?}"); + let nostr_hex_sk = auth.token(); + let issue_res = reissue_contract(&nostr_hex_sk, request).await?; Ok((StatusCode::OK, Json(issue_res))) } @@ -352,6 +368,42 @@ async fn co_retrieve( } } +async fn co_metadata( + Path((pk, name)): Path<(String, String)>, +) -> Result { + info!("GET /carbonado/{pk}/{name}/metadata"); + + let filepath = &handle_file(&pk, &name, 0).await?; + let mut metadata = FileMetadata::default(); + match OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&filepath) + { + Ok(file) => { + let present_header = match carbonado::file::Header::try_from(&file) { + Ok(header) => header, + _ => return Ok((StatusCode::OK, Json(metadata))), + }; + + metadata.filename = present_header.file_name(); + metadata.metadata = present_header.metadata.unwrap_or_default(); + } + Err(err) => match err.kind() { + ErrorKind::NotFound => { + fs::write(&filepath, &vec![]).await?; + } + _ => { + error!("error in POST /carbonado/{pk}/{name}: {err}"); + return Err(err.into()); + } + }, + } + + Ok((StatusCode::OK, Json(metadata))) +} + async fn status() -> Result { let cc = CacheControl::new().with_no_cache(); @@ -380,6 +432,7 @@ async fn main() -> Result<()> { let app = Router::new() .route("/issue", post(issue)) + .route("/reissue", post(reissue)) .route("/selfissue", post(self_issue)) .route("/invoice", post(invoice)) // .route("/psbt", post(psbt)) @@ -405,6 +458,7 @@ async fn main() -> Result<()> { .route("/carbonado/status", get(status)) .route("/carbonado/:pk/:name", post(co_store)) .route("/carbonado/:pk/:name", get(co_retrieve)) + .route("/carbonado/:pk/:name/metadata", get(co_metadata)) .layer(CorsLayer::permissive()); let network = get_network().await; diff --git a/src/carbonado.rs b/src/carbonado.rs index d1fc2b19..c229b556 100644 --- a/src/carbonado.rs +++ b/src/carbonado.rs @@ -13,6 +13,7 @@ use percent_encoding::utf8_percent_encode; pub mod constants; +use crate::structs::FileMetadata; #[cfg(not(feature = "server"))] use crate::{ carbonado::constants::FORM, @@ -20,14 +21,20 @@ use crate::{ }; #[cfg(not(feature = "server"))] -pub async fn store(sk: &str, name: &str, input: &[u8]) -> Result<()> { +pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option>) -> Result<()> { let level = 15; let sk = hex::decode(sk)?; let secret_key = SecretKey::from_slice(&sk)?; let public_key = PublicKey::from_secret_key_global(&secret_key); let pk = public_key.serialize(); let pk_hex = hex::encode(pk); - let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level)?; + + let mut meta: Option<[u8; 8]> = None; + if let Some(metadata) = metadata { + meta = Some(metadata.try_into().expect("invalid metadata size")); + } + + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, meta)?; let endpoint = CARBONADO_ENDPOINT.read().await.to_string(); let name = utf8_percent_encode(name, FORM); let network = NETWORK.read().await.to_string(); @@ -58,20 +65,61 @@ pub async fn store(sk: &str, name: &str, input: &[u8]) -> Result<()> { } #[cfg(feature = "server")] -pub async fn store(sk: &str, name: &str, input: &[u8]) -> Result<()> { +pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option>) -> Result<()> { let level = 15; let sk = hex::decode(sk)?; let secret_key = SecretKey::from_slice(&sk)?; let public_key = PublicKey::from_secret_key_global(&secret_key); let pk = public_key.serialize(); let pk_hex = hex::encode(pk); - let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level)?; + + let mut meta: Option<[u8; 8]> = None; + if let Some(metadata) = metadata { + meta = Some(metadata.try_into().expect("invalid metadata size")); + } + + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, meta)?; let filepath = handle_file(&pk_hex, name, body.len()).await?; fs::write(filepath, body).await?; Ok(()) } +#[cfg(not(feature = "server"))] +pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { + let sk = hex::decode(sk)?; + let secret_key = SecretKey::from_slice(&sk)?; + let public_key = PublicKey::from_secret_key_global(&secret_key); + let pk = public_key.to_hex(); + + let endpoint = CARBONADO_ENDPOINT.read().await.to_string(); + let name = utf8_percent_encode(name, FORM); + let network = NETWORK.read().await.to_string(); + let url = format!("{endpoint}/{pk}/{network}-{name}/metadata"); + let client = reqwest::Client::new(); + let response = client + .get(&url) + .header("Accept", "application/octet-stream") + .header("Cache-Control", "no-cache") + .send() + .await + .context(format!("Error sending JSON POST request to {url}"))?; + + let status_code = response.status().as_u16(); + + if status_code != 200 { + let response_text = response.text().await.context(format!( + "Error in parsing server response for POST JSON request to {url}" + ))?; + return Err(anyhow!( + "Error in retrieving carbonado file, status: {status_code} error: {response_text}" + )); + } + + let result = response.json::().await?; + Ok(result) +} + #[cfg(not(feature = "server"))] pub async fn retrieve(sk: &str, name: &str) -> Result> { let sk = hex::decode(sk)?; @@ -107,11 +155,37 @@ pub async fn retrieve(sk: &str, name: &str) -> Result> { if encoded.is_empty() { Ok(Vec::new()) } else { - let (_header, decoded) = carbonado::file::decode(&sk, &encoded)?; + let (_, decoded) = carbonado::file::decode(&sk, &encoded)?; Ok(decoded) } } +#[cfg(feature = "server")] +pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { + use crate::constants::NETWORK; + + let sk = hex::decode(sk)?; + let secret_key = SecretKey::from_slice(&sk)?; + let public_key = PublicKey::from_secret_key_global(&secret_key); + let pk = public_key.to_hex(); + + let network = NETWORK.read().await.to_string(); + let mut final_name = name.to_string(); + if !name.contains(&network) { + final_name = format!("{network}-{name}"); + } + + let filepath = handle_file(&pk, &final_name, 0).await?; + let bytes = fs::read(filepath).await?; + + let (header, _) = carbonado::file::decode(&sk, &bytes)?; + let mut result = FileMetadata::default(); + result.filename = header.file_name(); + result.metadata = header.metadata.unwrap_or_default(); + + Ok(result) +} + #[cfg(feature = "server")] pub async fn retrieve(sk: &str, name: &str) -> Result> { use crate::constants::NETWORK; @@ -133,7 +207,8 @@ pub async fn retrieve(sk: &str, name: &str) -> Result> { if bytes.is_empty() { Ok(Vec::new()) } else { - let (_header, decoded) = carbonado::file::decode(&sk, &bytes)?; + let (_, decoded) = carbonado::file::decode(&sk, &bytes)?; + Ok(decoded) } } diff --git a/src/constants.rs b/src/constants.rs index af9392b0..42532bc4 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -125,6 +125,10 @@ pub async fn switch_network(network_str: &str) -> Result<()> { pub static LNDHUB_ENDPOINT: Lazy> = Lazy::new(|| RwLock::new(dot_env("LNDHUB_ENDPOINT"))); +// bitmask node +pub static BITMASK_ENDPOINT: Lazy> = + Lazy::new(|| RwLock::new(dot_env("BITMASK_ENDPOINT"))); + // carbonado pub static CARBONADO_ENDPOINT: Lazy> = Lazy::new(|| RwLock::new(dot_env("CARBONADO_ENDPOINT"))); diff --git a/src/rgb.rs b/src/rgb.rs index 4af13767..d06d7dfb 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -1,5 +1,6 @@ use std::{collections::BTreeMap, str::FromStr}; +use crate::rgb::structs::RgbAccount; use ::psbt::serialize::Serialize; use amplify::{confinement::U16, hex::ToHex}; use anyhow::{anyhow, Result}; @@ -46,12 +47,13 @@ use crate::{ wallet::list_allocations, }, structs::{ - AcceptRequest, AcceptResponse, AssetType, ContractResponse, ContractsResponse, - ImportRequest, InterfaceDetail, InterfacesResponse, InvoiceRequest, InvoiceResponse, - IssueRequest, IssueResponse, NextAddressResponse, NextUtxoResponse, NextUtxosResponse, - PsbtRequest, PsbtResponse, RgbTransferRequest, RgbTransferResponse, SchemaDetail, - SchemasResponse, WatcherDetailResponse, WatcherRequest, WatcherResponse, - WatcherUtxoResponse, + AcceptRequest, AcceptResponse, AssetType, ContractMetadata, ContractResponse, + ContractsResponse, ImportRequest, InterfaceDetail, InterfacesResponse, InvoiceRequest, + InvoiceResponse, IssueMetaRequest, IssueMetadata, IssueRequest, IssueResponse, + NewCollectible, NextAddressResponse, NextUtxoResponse, NextUtxosResponse, PsbtRequest, + PsbtResponse, ReIssueRequest, ReIssueResponse, RgbTransferRequest, RgbTransferResponse, + SchemaDetail, SchemasResponse, UDADetail, WatcherDetailResponse, WatcherRequest, + WatcherResponse, WatcherUtxoResponse, }, }; @@ -72,8 +74,107 @@ use self::{ }; /// RGB Operations -#[allow(clippy::too_many_arguments)] pub async fn issue_contract(sk: &str, request: IssueRequest) -> Result { + let mut stock = retrieve_stock(sk, ASSETS_STOCK).await?; + let mut rgb_account = retrieve_wallets(sk, ASSETS_WALLETS).await?; + + let resp = issue_rgb_contract(request, &mut stock, &mut rgb_account).await; + store_stock(sk, ASSETS_STOCK, &stock).await?; + store_wallets(sk, ASSETS_WALLETS, &rgb_account).await?; + + resp +} + +pub async fn reissue_contract(sk: &str, request: ReIssueRequest) -> Result { + let mut stock = Stock::default(); + let mut rgb_account = retrieve_wallets(sk, ASSETS_WALLETS).await?; + + let mut reissue_resp = vec![]; + for contract in request.contracts { + let ContractResponse { + ticker, + name, + description, + supply, + contract_id: _, + iimpl_id: _, + iface, + precision, + balance: _, + allocations, + contract: _, + genesis: _, + meta: contract_meta, + } = contract; + + let seals: Vec = allocations + .into_iter() + .map(|alloc| format!("tapret1st:{}", alloc.utxo)) + .collect(); + let seal = seals.first().unwrap().to_owned(); + + let mut meta = None; + if let Some(contract_meta) = contract_meta { + meta = Some(match contract_meta.meta() { + ContractMetadata::UDA(uda) => IssueMetaRequest(IssueMetadata::UDA(uda.media)), + ContractMetadata::Collectible(colectibles) => { + let mut items = vec![]; + for collectible_item in colectibles { + let UDADetail { + ticker, + name, + token_index: _, + description, + balance: _, + media, + allocations: _, + } = collectible_item; + + let new_item = NewCollectible { + ticker, + name, + description, + media, + }; + + items.push(new_item); + } + + IssueMetaRequest(IssueMetadata::Collectible(items)) + } + }) + } + + let req = IssueRequest { + ticker, + name, + description, + supply, + precision, + iface, + seal, + meta, + }; + + let resp = issue_rgb_contract(req, &mut stock, &mut rgb_account) + .await + .expect("re-issue contract failed"); + reissue_resp.push(resp); + } + + store_stock(sk, ASSETS_STOCK, &stock).await?; + store_wallets(sk, ASSETS_WALLETS, &rgb_account).await?; + + Ok(ReIssueResponse { + contracts: reissue_resp, + }) +} + +async fn issue_rgb_contract( + request: IssueRequest, + mut stock: &mut Stock, + rgb_account: &mut RgbAccount, +) -> Result { let IssueRequest { ticker, name, @@ -84,8 +185,6 @@ pub async fn issue_contract(sk: &str, request: IssueRequest) -> Result Result Result<()> { let data = stock.to_strict_serialized::()?; - - store(sk, name, &data).await + store(sk, name, &data, Some(RGB_STRICT_TYPE_VERSION.to_vec())).await } pub async fn retrieve_stock(sk: &str, name: &str) -> Result { @@ -27,7 +27,7 @@ pub async fn retrieve_stock(sk: &str, name: &str) -> Result { pub async fn store_wallets(sk: &str, name: &str, rgb_wallets: &RgbAccount) -> Result<()> { let data = to_allocvec(rgb_wallets)?; - store(sk, name, &data).await + store(sk, name, &data, Some(RGB_STRICT_TYPE_VERSION.to_vec())).await } pub async fn retrieve_wallets(sk: &str, name: &str) -> Result { diff --git a/src/rgb/constants.rs b/src/rgb/constants.rs index 43481d06..971a031b 100644 --- a/src/rgb/constants.rs +++ b/src/rgb/constants.rs @@ -2,3 +2,5 @@ pub const LIB_NAME_BITMASK: &str = "bitmask"; pub const RGB_CHANGE_INDEX: &str = "0"; pub const RGB_PSBT_TAPRET: &str = "TAPRET"; pub const RGB_DEFAULT_NAME: &str = "default"; +pub const RGB_OLDEST_VERSION: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; +pub const RGB_STRICT_TYPE_VERSION: [u8; 8] = [b'r', b'g', b'b', b's', b't', b'1', b'3', b'0']; diff --git a/src/rgb/contract.rs b/src/rgb/contract.rs index 3b35d46b..392ac22a 100644 --- a/src/rgb/contract.rs +++ b/src/rgb/contract.rs @@ -68,7 +68,7 @@ where let mut ticker = String::new(); let mut name = String::new(); - let mut precision = 0; + let mut precision: u8 = 0; let mut description = String::new(); let ty: FieldName = FieldName::from("spec"); @@ -95,7 +95,7 @@ where } if let Some(StrictVal::Enum(en)) = fields.get(&FieldName::from("precision")) { let val = en.unwrap_ord(); - precision = val as u64; + precision = val; } }; } diff --git a/src/structs.rs b/src/structs.rs index 2bc14a85..6ea968bc 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -132,6 +132,13 @@ pub struct SelfIssueRequest { pub meta: Option, } +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct ReIssueRequest { + /// previous contracts + pub contracts: Vec, +} + #[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct IssueMetaRequest(pub IssueMetadata); @@ -232,6 +239,12 @@ pub struct GenesisFormats { pub armored: String, } +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct ReIssueResponse { + pub contracts: Vec, +} + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub enum AssetType { @@ -272,7 +285,7 @@ pub struct ContractResponse { /// Amount of the asset pub supply: u64, /// Precision of the asset - pub precision: u64, + pub precision: u8, /// The user contract balance pub balance: u64, /// The contract allocations @@ -293,6 +306,10 @@ impl ContractMeta { pub fn with(metadata: ContractMetadata) -> Self { ContractMeta(metadata) } + + pub fn meta(self) -> ContractMetadata { + self.0 + } } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -536,6 +553,7 @@ pub struct AllocationDetail { /// My Allocation? pub is_mine: bool, /// Allocation spent? + #[serde(skip)] pub is_spent: bool, } @@ -640,3 +658,10 @@ pub struct ExportRequestMini { /// ContractId of the asset to export FROM the node pub asset: String, } + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct FileMetadata { + pub filename: String, + pub metadata: [u8; 8], +} diff --git a/src/web.rs b/src/web.rs index 577cb214..404fbad6 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,6 +1,6 @@ use crate::structs::{ - AcceptRequest, ImportRequest, InvoiceRequest, IssueRequest, PsbtRequest, RgbTransferRequest, - SecretString, SignPsbtRequest, WatcherRequest, + AcceptRequest, ImportRequest, InvoiceRequest, IssueRequest, PsbtRequest, ReIssueRequest, + RgbTransferRequest, SecretString, SignPsbtRequest, WatcherRequest, }; // use crate::{carbonado, lightning, rgb}; @@ -320,6 +320,22 @@ pub mod rgb { }) } + #[allow(clippy::too_many_arguments)] + #[wasm_bindgen] + pub fn reissue_contract(nostr_hex_sk: String, request: JsValue) -> Promise { + set_panic_hook(); + + future_to_promise(async move { + let req: ReIssueRequest = serde_wasm_bindgen::from_value(request).unwrap(); + match crate::rgb::reissue_contract(&nostr_hex_sk, req).await { + Ok(result) => Ok(JsValue::from_string( + serde_json::to_string(&result).unwrap(), + )), + Err(err) => Err(JsValue::from_string(err.to_string())), + } + }) + } + #[wasm_bindgen] pub fn rgb_create_invoice(nostr_hex_sk: String, request: JsValue) -> Promise { set_panic_hook(); @@ -658,11 +674,16 @@ pub mod carbonado { use super::*; #[wasm_bindgen] - pub fn store(secret_key: String, name: String, data: Vec) -> Promise { + pub fn store( + secret_key: String, + name: String, + data: Vec, + metadata: Option>, + ) -> Promise { set_panic_hook(); future_to_promise(async move { - match crate::carbonado::store(&secret_key, &name, &data).await { + match crate::carbonado::store(&secret_key, &name, &data, metadata).await { Ok(result) => Ok(JsValue::from_string( serde_json::to_string(&result).unwrap(), )), @@ -689,6 +710,20 @@ pub mod carbonado { }) } + #[wasm_bindgen] + pub fn retrieve_metadata(secret_key: String, name: String) -> Promise { + set_panic_hook(); + + future_to_promise(async move { + match crate::carbonado::retrieve_metadata(&secret_key, &name).await { + Ok(result) => Ok(JsValue::from_string( + serde_json::to_string(&result).unwrap(), + )), + Err(err) => Err(JsValue::from_string(err.to_string())), + } + }) + } + #[wasm_bindgen] pub fn encode_hex(bytes: Vec) -> String { set_panic_hook(); diff --git a/tests/rgb.rs b/tests/rgb.rs index f296722b..464ffcf2 100644 --- a/tests/rgb.rs +++ b/tests/rgb.rs @@ -28,4 +28,8 @@ mod rgb { mod imports; mod std; } + + mod sre { + mod st130; + } } diff --git a/tests/rgb/sre/st130.rs b/tests/rgb/sre/st130.rs new file mode 100644 index 00000000..826d01a2 --- /dev/null +++ b/tests/rgb/sre/st130.rs @@ -0,0 +1,124 @@ +#![cfg(not(target_arch = "wasm32"))] +use crate::rgb::integration::utils::ISSUER_MNEMONIC; +use anyhow::{anyhow, Context}; +use bitmask_core::carbonado::{retrieve_metadata, store}; +use bitmask_core::structs::WatcherRequest; +use bitmask_core::{ + bitcoin::save_mnemonic, + carbonado::constants::FORM, + constants::{storage_keys::ASSETS_STOCK, BITMASK_ENDPOINT, NETWORK}, + rgb::{constants::RGB_OLDEST_VERSION, reissue_contract}, + structs::{ContractsResponse, ReIssueRequest, SecretString}, +}; +use hex::FromHex; +use nostr_sdk::key::{PublicKey, SecretKey}; +use percent_encoding::utf8_percent_encode; +use reqwest::Client; + +#[tokio::test] +#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.3.0)"] +async fn allow_re_issue_rgb_contracts() -> anyhow::Result<()> { + let bitmask_endpoint = BITMASK_ENDPOINT.read().await.to_string(); + let issuer_keys = save_mnemonic( + &SecretString(ISSUER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + + // 0. Create Watcher + let issuer_sk = &issuer_keys.private.nostr_prv; + let client = Client::new(); + let endpoint = format!("{bitmask_endpoint}/watcher"); + let watch_req = WatcherRequest { + name: "default".to_string(), + xpub: issuer_keys.public.watcher_xpub.clone(), + force: true, + }; + let resp = client + .post(&endpoint) + .json(&watch_req) + .bearer_auth(issuer_sk) + .send() + .await; + assert!(resp.is_ok()); + + // 0. Prepare Data Test + let file_name = ASSETS_STOCK.to_string(); + let input = Vec::::from_hex(STOCK_ST_120)?; + + let resp = store_in_server(issuer_sk, &file_name, &input, None).await; + assert!(resp.is_ok()); + + // 1. Retrieve metadata + let fake_file_name = "fake-name.c15"; + let resp = store(issuer_sk, &fake_file_name, &input, None).await; + assert!(resp.is_ok()); + + let resp = retrieve_metadata(issuer_sk, &fake_file_name).await; + assert!(resp.is_ok()); + + // 2. Retrieve contracts + let file_header = resp?; + if file_header.metadata == RGB_OLDEST_VERSION { + let endpoint = format!("{bitmask_endpoint}/contracts"); + + let result = client.get(&endpoint).bearer_auth(issuer_sk).send().await?; + + let resp = result.json::().await?; + let reissue_req = ReIssueRequest { + contracts: resp.contracts, + }; + + // 2. ReIssue contracts + let reissue_resp = reissue_contract(issuer_sk, reissue_req).await; + assert!(reissue_resp.is_ok()); + } + + Ok(()) +} + +async fn store_in_server( + sk: &str, + name: &str, + input: &[u8], + metadata: Option<[u8; 8]>, +) -> anyhow::Result<()> { + let level = 15; + let sk = hex::decode(sk)?; + let secret_key = SecretKey::from_slice(&sk)?; + let public_key = PublicKey::from_secret_key_global(&secret_key); + let pk = public_key.serialize(); + let pk_hex = hex::encode(pk); + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, metadata)?; + let endpoint = BITMASK_ENDPOINT.read().await.to_string(); + let name = utf8_percent_encode(name, FORM); + let network = NETWORK.read().await.to_string(); + let url = format!("{endpoint}/carbonado/{pk_hex}/{network}-{name}"); + let client = reqwest::Client::new(); + let response = client + .post(&url) + .body(body) + .header("Content-Type", "application/octet-stream") + .header("Cache-Control", "no-cache") + .send() + .await + .context(format!("Error sending JSON POST request to {url}"))?; + + let status_code = response.status().as_u16(); + + if status_code != 200 { + let response_text = response.text().await.context(format!( + "Error in parsing server response for POST JSON request to {url}" + ))?; + + println!("{}", url); + + Err(anyhow!( + "Error in storing carbonado file, status: {status_code} error: {response_text}" + )) + } else { + Ok(()) + } +} + +const STOCK_ST_120: &str = "02d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd000000030300cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e4300100d007b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100d107b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010001d007010800c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b103030001000100d00701000100d1070100010001d0070100ffff000001d007c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10001d0070100ffff01d0070100ffff0037000017acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd010b524742436f6e7472616374044e616d65050198db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d81bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0107426974636f696e0554784f757406020576616c7565cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00c7363726970745075626b65794a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba1df1d11643dd30bf0b583883dfa61289186277ace4ad075e3c67ac0b83802eaa01035374640a486578446563436170730310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e4623bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0107426974636f696e095369675363726970740501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c3027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000403719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac600040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e38fd0b174ca8528da005d978de7dd5a2a763bb67e42ca25b935edf451344229e01035374640a416c706861536d616c6c031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e00050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d104693e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100000000000000000ffff0000000000004a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba0107426974636f696e0c5363726970745075626b65790501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c52740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560107426974636f696e084f7574706f696e7406020474786964b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab404766f7574fd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d5577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b000360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377f55accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b01035374640e41736369695072696e7461626c65035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e58a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066170000445cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80600085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b0100000000000000080000000000000060fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec010b524742436f6e74726163740b41737365744e616d696e670603067469636b657292e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506046e616d6517acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd0764657461696c733719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac661cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a25510000161dac6b5168357edbd878765f0382f79d864835c01c7e3a0d0747a235404c3ba010353746408416c7068614e756d033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a66ff6ddb2093d3e48033bbd707da2588df6a93d25b7d419c0592cadb31e8a2da0107426974636f696e02547806040776657273696f6e6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e8863206696e70757473e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba076f75747075747376ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f3086c6f636b54696d656f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e886320107426974636f696e055478566572050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066176c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110000086f0cbcc3130d8fdbd168f60ebb2477f344d85659ca1fc56d84b235072b67c74501035374640e416c7068614e756d4c6f64617368033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a6f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b0107426974636f696e084c6f636b54696d650501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253175b7c2e75f4dbfc3728201bc72c62986a08f2734cb3e50f32e6aad2f21343f5a010353746409416c70686143617073031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a76ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f300081bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0000000000000000ffffffffffffffff8a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffff0000000000008df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40107426974636f696e045478496e06040a707265764f757470757452740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560973696753637269707423bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0873657175656e6365bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff7077769746e657373bd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff791281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469010b524742436f6e74726163740744657461696c730501d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f92e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506010b524742436f6e7472616374065469636b657205015cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80698db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d800085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b01000000000000002800000000000000a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffffffffffffffffa788a36d6e35c945b224869165f2844711784f55b6b484b2f21f35397170ad8401035374640255340310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fae6894c8d85e1f4b6e7a31dabf56f6a09c1f423f6ce5fd49ea56bc025cb4f22301035374640c416c7068614e756d44617368033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7ab0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a5400073027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9962000b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010b524742436f6e74726163741152696361726469616e436f6e747261637405013e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd8989010b524742436f6e747261637412446976697369626c654173736574537065630602066e616d696e6760fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec09707265636973696f6ec554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab40107426974636f696e04547869640501b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54b9ef64121db10df182d4df713abb2b2e97a73f8f9c116f81f54577c3e0bf015b010353746403446563030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80010b524742436f6e74726163740f50726f6f664f6652657365727665730602047574786fb1e43bec82e3821b2d7ccee89a7d213da8b77eea0518bcfa4f6d6f8dfe0296de0570726f6f668a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caaebbd8604f99b5c9047de07d559069a286d27c94143106e2f5eae266ae44f7168701035374640c416c706861436170734e756d0324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5abd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff70107426974636f696e075769746e6573730501f5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c548bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff70107426974636f696e055365714e6f0501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5010b524742436f6e747261637409507265636973696f6e03130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f12c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b1000000cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e430010b524742436f6e74726163740954696d657374616d70050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c752606617cb958efe9c6d304f13222e2a4907124e86e7ea1c5a74e24c3e2235f6c4d2a9a501035374640b486578446563536d616c6c0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00107426974636f696e045361747305016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b11d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100100000000000000ff00000000000000e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000004e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba00088df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40000000000000000fffffffffffffffff27e112e62134308df24f66cd6a133e473d72977d65f49467f1fd8a4d92a13c7010353746404426f6f6c03020566616c736500047472756501f41f2a6324dcada5162bb3034f7c2a19ad40b9124fb467e44c5a0d772c430d8e010353746405416c7068610334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7af5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c5480008a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe0000000000000000fffffffffffffffff82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c0107426974636f696e0b53637269707442797465730501a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fefd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d0107426974636f696e04566f75740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253100015650fb29bac1c7616f976727b1e81234887ad96e7056f5a3cc99e4a8378b31480c00035247420300d0d007000000010004d0075650fb29bac1c7616f976727b1e81234887ad96e7056f5a3cc99e4a8378b3148000001dd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce900d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bddd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce90303000763726561746564d0070473706563d107057465726d7301d0070b62656e65666963696172790001d007085472616e7366657200dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d4000000050300cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001003408b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd898901003508b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae37798610700100360806df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c01003808869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f60100013408025d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa81000c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b105030001000100340801000100350801000100360800000100380800000100013408010001000000013408c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b100013408010001000134080100010000580000017447c77d2367544618e2aaf4e680659b9df075544650b5a4bbab699ea258c800040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d651da55835280aba3b02d1b5d02fc3fc47c267e8ed85554b0e7d13beed5c132b30065602cf1069e5dcfccabc7fd98ca570ce4eb972bddfb8c63633483dd519c19d00085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b0100000000000000400000000000000006df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c0105524742323109546f6b656e44617461060805696e646578d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d7664067469636b6572d669d8d150ff6a2e7486568b066e2fb43e4efe6aab93d103d8f559d14a6ccd15046e616d65017447c77d2367544618e2aaf4e680659b9df075544650b5a4bbab699ea258c80764657461696c73181998eeb65f373753d54b4983424050c38cb464d587d6a3741a13c69abfdc1007707265766965774cc79dab63f53b172bd53af42d3c1b9e36fdc5ba19ec625dcf99cf9ee6d23178056d65646961ba7da437dd2009266764a53302be280bec57a35edea906c42185c96e1a1d4e840b6174746163686d656e74730f1b2b5d80322340d1064fcfc7b82c98002836666b576b1eb7baf1a2d2756cff0872657365727665730c90d2700887419382cbcbd28c78d7c1b112602e4438551c3ca58ae68a975cbc0718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7010552474232310949737375654d65746106010872657365727665734d09d713e21e9bbabd91ffe3ac096102dcfe3ed8994f7089158532a139a024bb09317e1367c0edbbfffb675b5329d6554a0ec62580c5e5a5215af318270a88b3010552474232310d4f776e65644672616374696f6e05016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110c90d2700887419382cbcbd28c78d7c1b112602e4438551c3ca58ae68a975cbc00040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65affcae68cd21c376584c7b4a68de738dfad6386a7d6d3a7bbb348227976d14f80f1b2b5d80322340d1064fcfc7b82c98002836666b576b1eb7baf1a2d2756cff000a0001a84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e20000000000000000140000000000000017acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd010b524742436f6e7472616374044e616d65050198db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d8181998eeb65f373753d54b4983424050c38cb464d587d6a3741a13c69abfdc1000040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65b360cb3d1a1ce2559dd5cc11d2b3164467211559b80a239b16d081f394fa5b531bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0107426974636f696e0554784f757406020576616c7565cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00c7363726970745075626b65794a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba1da55835280aba3b02d1b5d02fc3fc47c267e8ed85554b0e7d13beed5c132b3000050117acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd1df1d11643dd30bf0b583883dfa61289186277ace4ad075e3c67ac0b83802eaa01035374640a486578446563436170730310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e4623bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0107426974636f696e095369675363726970740501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c3027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000403719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac600040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e38fd0b174ca8528da005d978de7dd5a2a763bb67e42ca25b935edf451344229e01035374640a416c706861536d616c6c031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e00050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d104693e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100000000000000000ffff000000000000470ad9ae9cbc8fa7428330b0c0a4fb32d1f9fc30a94eaa4b3c41145b849a56e9000501a84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e2497c7eb9391a079a38d92afdde2e4eec03a9a37987201d5ab5b14d45c17b250d010552474232310d456e67726176696e67446174610602096170706c696564546fd3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d766407636f6e74656e747b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da24a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba0107426974636f696e0c5363726970745075626b65790501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c4cc79dab63f53b172bd53af42d3c1b9e36fdc5ba19ec625dcf99cf9ee6d2317800040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d656022af4d5e00c75978b1d60421997e0b227b395dce5e52da8e030b6ae9174a444d09d713e21e9bbabd91ffe3ac096102dcfe3ed8994f7089158532a139a024bb0009ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc800000000000000000ffff0000000000004f46dce8279430081e45f623d0d618ed7f52efb553bc241b0d2ae7ec601c1a5c01055247423231094d6564696154797065060304747970655538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa0773756274797065b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b90763686172736574b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b952740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560107426974636f696e084f7574706f696e7406020474786964b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab404766f7574fd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d5538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa010552474232310c4d656469615265674e616d650501065602cf1069e5dcfccabc7fd98ca570ce4eb972bddfb8c63633483dd519c19d5577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b000360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377f55accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b01035374640e41736369695072696e7461626c65035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e58a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066170000445cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80600085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b010000000000000008000000000000005d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa810010552474232310a416c6c6f636174696f6e0502d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d766409317e1367c0edbbfffb675b5329d6554a0ec62580c5e5a5215af318270a88b36022af4d5e00c75978b1d60421997e0b227b395dce5e52da8e030b6ae9174a440005017b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da260fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec010b524742436f6e74726163740b41737365744e616d696e670603067469636b657292e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506046e616d6517acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd0764657461696c733719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac661cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a25510000161dac6b5168357edbd878765f0382f79d864835c01c7e3a0d0747a235404c3ba010353746408416c7068614e756d033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a66ff6ddb2093d3e48033bbd707da2588df6a93d25b7d419c0592cadb31e8a2da0107426974636f696e02547806040776657273696f6e6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e8863206696e70757473e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba076f75747075747376ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f3086c6f636b54696d656f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b695eb06afff78803151c5c7c1620648f52dca30526ce3ec3fea1ad7fcab75a8a000855accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b010000000000000014000000000000006963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e886320107426974636f696e055478566572050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066176c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110000086f0cbcc3130d8fdbd168f60ebb2477f344d85659ca1fc56d84b235072b67c74501035374640e416c7068614e756d4c6f64617368033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a6f23e8a03955547d9bd76db47bb7e5eea3792d5f8f223c790cc2b5eed658c09f0005015538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa6f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b0107426974636f696e084c6f636b54696d650501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253175b7c2e75f4dbfc3728201bc72c62986a08f2734cb3e50f32e6aad2f21343f5a010353746409416c70686143617073031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a76ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f300081bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0000000000000000ffffffffffffffff7b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da2010552474232310d456d6265646465644d65646961060204747970654f46dce8279430081e45f623d0d618ed7f52efb553bc241b0d2ae7ec601c1a5c04646174618a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f6010552474232310e4174746163686d656e74547970650602026964cd2a948954a0dc1dd1a4e04145245638af3f544c133c68bf1af183cb3346668a046e616d659819b0f8b92eac0f19205791b5016c23f78f78560bb47d74e266a9c24b0cf33e8a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffff0000000000008aa05647e0f89c231194d76e4f776ef7d3255028c484cb63a8a68f7d0251695e00050192e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be8429835068df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40107426974636f696e045478496e06040a707265764f757470757452740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560973696753637269707423bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0873657175656e6365bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff7077769746e657373bd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff79048212cad2ed6e09a3e853c904f71889286e17ec23d0a3b6326ecee721b7b9901055247423231054572726f720308106672616374696f6e4f766572666c6f77010e6e6f6e457175616c56616c756573020c696e76616c696450726f6f660314696e73756666696369656e7452657365727665730415697373756545786365656473416c6c6f77616e636506126e6f6e4672616374696f6e616c546f6b656e07126e6f6e456e6772617661626c65546f6b656e0815696e76616c69644174746163686d656e74547970650991281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469010b524742436f6e74726163740744657461696c730501d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f92e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506010b524742436f6e7472616374065469636b657205015cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb8069819b0f8b92eac0f19205791b5016c23f78f78560bb47d74e266a9c24b0cf33e010552474232310e4174746163686d656e744e616d650501695eb06afff78803151c5c7c1620648f52dca30526ce3ec3fea1ad7fcab75a8a98db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d800085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b01000000000000002800000000000000a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffffffffffffffffa788a36d6e35c945b224869165f2844711784f55b6b484b2f21f35397170ad8401035374640255340310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e2010552474232310a4174746163686d656e7406020474797065869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f606646967657374b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54ae6894c8d85e1f4b6e7a31dabf56f6a09c1f423f6ce5fd49ea56bc025cb4f22301035374640c416c7068614e756d44617368033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7aaffcae68cd21c376584c7b4a68de738dfad6386a7d6d3a7bbb348227976d14f8000501ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a5400073027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9962000b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010b524742436f6e74726163741152696361726469616e436f6e747261637405013e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd8989010b524742436f6e747261637412446976697369626c654173736574537065630602066e616d696e6760fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec09707265636973696f6ec554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5b360cb3d1a1ce2559dd5cc11d2b3164467211559b80a239b16d081f394fa5b5300050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b900040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d656f23e8a03955547d9bd76db47bb7e5eea3792d5f8f223c790cc2b5eed658c09fb9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab40107426974636f696e04547869640501b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54b9ef64121db10df182d4df713abb2b2e97a73f8f9c116f81f54577c3e0bf015b010353746403446563030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80010b524742436f6e74726163740f50726f6f664f6652657365727665730602047574786fb1e43bec82e3821b2d7ccee89a7d213da8b77eea0518bcfa4f6d6f8dfe0296de0570726f6f668a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caaeba7da437dd2009266764a53302be280bec57a35edea906c42185c96e1a1d4e8400040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65470ad9ae9cbc8fa7428330b0c0a4fb32d1f9fc30a94eaa4b3c41145b849a56e9bbd8604f99b5c9047de07d559069a286d27c94143106e2f5eae266ae44f7168701035374640c416c706861436170734e756d0324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5abd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff70107426974636f696e075769746e6573730501f5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c548bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff70107426974636f696e055365714e6f0501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c1f252f38965138fc5cb730e49eda0f7f792ed6b88b2e17739d6410d251b1514010552474232310a4974656d73436f756e740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5010b524742436f6e747261637409507265636973696f6e03130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f12c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b1000000cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e430010b524742436f6e74726163740954696d657374616d70050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c752606617cb958efe9c6d304f13222e2a4907124e86e7ea1c5a74e24c3e2235f6c4d2a9a501035374640b486578446563536d616c6c0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00107426974636f696e045361747305016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b11cd2a948954a0dc1dd1a4e04145245638af3f544c133c68bf1af183cb3346668a000001d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100100000000000000ff00000000000000d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d7664010552474232310a546f6b656e496e6465780501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531d669d8d150ff6a2e7486568b066e2fb43e4efe6aab93d103d8f559d14a6ccd1500040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d658aa05647e0f89c231194d76e4f776ef7d3255028c484cb63a8a68f7d0251695ee27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000004e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba00088df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40000000000000000fffffffffffffffff27e112e62134308df24f66cd6a133e473d72977d65f49467f1fd8a4d92a13c7010353746404426f6f6c03020566616c736500047472756501f41f2a6324dcada5162bb3034f7c2a19ad40b9124fb467e44c5a0d772c430d8e010353746405416c7068610334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7af5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c5480008a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe0000000000000000fffffffffffffffff82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c0107426974636f696e0b53637269707442797465730501a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fefd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d0107426974636f696e04566f75740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000000000191da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b00dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d491da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b0403000763726561746564340804737065633508057465726d73360806746f6b656e730134080b62656e656669636961727900013408085472616e73666572000291da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b00055247423231060f6174746163686d656e74547970657301869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f60001076372656174656401cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001000a656e67726176696e677301497c7eb9391a079a38d92afdde2e4eec03a9a37987201d5ab5b14d45c17b250d0001047370656301b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100057465726d7301b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010006746f6b656e730106df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c0001030a61737365744f776e6572055d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa81000000112696e666c6174696f6e416c6c6f77616e636505c1f252f38965138fc5cb730e49eda0f7f792ed6b88b2e17739d6410d251b15140100010b75706461746552696768740101000000010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7050f6174746163686d656e745479706573000000ffff0763726561746564000100010004737065630001000100057465726d73000100010006746f6b656e73000000ffff030a61737365744f776e6572000000ffff12696e666c6174696f6e416c6c6f77616e6365000000ffff0b757064617465526967687400000001000004010304090407456e67726176650100010a656e67726176696e67730001000100010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000401020708010b62656e656669636961727905497373756501010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b702126e65774174746163686d656e745479706573010f6174746163686d656e7454797065730000ffff096e6577546f6b656e730106746f6b656e730000ffff0104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff00050103040609010b62656e65666963696172790652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff0003010207010b62656e6566696369617279009048212cad2ed6e09a3e853c904f71889286e17ec23d0a3b6326ecee721b7b9901085472616e73666572dd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce900055247423230060c6275726e6564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a0001076372656174656401cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001000c697373756564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a00010e7265706c61636564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a0001047370656301b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100057465726d7301b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae37798610700100050a61737365744f776e657202000001096275726e45706f636801010000096275726e52696768740101000112696e666c6174696f6e416c6c6f77616e6365020100010b75706461746552696768740101000000010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b704076372656174656400010001000c697373756564537570706c79000100010004737065630001000100057465726d730001000100040a61737365744f776e6572000000ffff096275726e45706f6368000000010012696e666c6174696f6e416c6c6f77616e6365000000ffff0b75706461746552696768740000000100000301030406044275726e0101f4bdcb47aa7db1caab5656f482e6788f22cf4534f93d506cdb350e13b9d0d9eb010c6275726e6564537570706c79000100010001047573656401096275726e526967687401000100010666757475726501096275726e52696768740000010000030103050005497373756501010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7010c697373756564537570706c7900010001000104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff000401030406010b62656e6566696369617279094f70656e45706f636801000001047573656401096275726e45706f63680100010002096275726e52696768740001000100046e65787401096275726e45706f636800000100000001096275726e52696768740652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265075265706c6163650101f4bdcb47aa7db1caab5656f482e6788f22cf4534f93d506cdb350e13b9d0d9eb010e7265706c61636564537570706c79000100010001047573656401096275726e526967687401000100020b62656e6566696369617279010a61737365744f776e65720000ffff0666757475726501096275726e526967687400000100000401020305010b62656e6566696369617279085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000102010b62656e65666963696172790031e4e2b06ffac24c5455a677c387081de1697ebb91ba71ef38825fc9301bc80301085472616e73666572021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f0000d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd8000000303000100040000000000d00701000c00044449424104444942410002d1070100060004004449424101d00701010003010030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f0000000022b15850d50f7ac1080500000000000000a1be14ae6fd7e13c777322802c58fd7d808f51184cfb2843bf594ffb97e790c600c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc0000dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d48000000403000100040000000000340801000c0004444942410444494241000235080100060004004449424136080100400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e6700000001340802010003013755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec74701000000393f83f1cb83ff340c0001000000010000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f00c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc000000000000000000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f03030001000000000000040000000000d007010000000000000c00044449424104444942410002d10701000000000000060004004449424100000000010000001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd00700000030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f00000000080500000000000000a1be14ae6fd7e13c777322802c58fd7d808f51184cfb2843bf594ffb97e790c6000000000000000000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bcdd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d400c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc040300010000000000000400000000003408010000000000000c000444494241044449424100023508010000000000000600040044494241360801000000000000400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e67000000000000000000000001000000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc340800003755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec747010000000c000100000001000000000000000000000000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f0000000100000030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f000000000100001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd0070000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc0000000100003755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec74701000000010000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc34080000000000000000"; diff --git a/tests/web_storage.rs b/tests/web_storage.rs index db36eace..a4e9ff15 100644 --- a/tests/web_storage.rs +++ b/tests/web_storage.rs @@ -21,7 +21,7 @@ async fn web_storage() { let data = b"Hello world!".to_vec(); info!("Testing web data store"); - resolve(store(sk.clone(), name.clone(), data.clone())).await; + resolve(store(sk.clone(), name.clone(), data.clone(), None)).await; info!("Testing web data retrieve"); let result: JsValue = resolve(retrieve(sk, name)).await; From 7984e567c5aacbbb07495accdb5cf3c7059280c7 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Thu, 29 Jun 2023 03:14:12 -0600 Subject: [PATCH 06/15] Fix additional clippy lints for integration tests. --- src/bin/bitmaskd.rs | 2 +- tests/rgb/integration/transfers.rs | 3 +-- tests/rgb/integration/utils.rs | 4 ++-- tests/rgb/sre/st130.rs | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/bin/bitmaskd.rs b/src/bin/bitmaskd.rs index 3268f987..ba8eafc2 100644 --- a/src/bin/bitmaskd.rs +++ b/src/bin/bitmaskd.rs @@ -57,7 +57,7 @@ async fn reissue( info!("POST /reissue {request:?}"); let nostr_hex_sk = auth.token(); - let issue_res = reissue_contract(&nostr_hex_sk, request).await?; + let issue_res = reissue_contract(nostr_hex_sk, request).await?; Ok((StatusCode::OK, Json(issue_res))) } diff --git a/tests/rgb/integration/transfers.rs b/tests/rgb/integration/transfers.rs index e38974d5..0fe995d1 100644 --- a/tests/rgb/integration/transfers.rs +++ b/tests/rgb/integration/transfers.rs @@ -93,7 +93,7 @@ async fn allow_issuer_make_conseq_transfers() -> anyhow::Result<()> { let new_alloc = issuer_contract .allocations .into_iter() - .find(|x| x.is_mine == true) + .find(|x| x.is_mine) .unwrap(); let psbt_resp = create_new_psbt( &issuer_resp.contract_id, @@ -1097,7 +1097,6 @@ async fn allows_spend_amount_from_two_different_transitions() -> anyhow::Result< .allocations .into_iter() .filter(|alloc| alloc.is_mine && !alloc.is_spent) - .map(|f| f) .collect(); assert_eq!(2, allocs.len()); diff --git a/tests/rgb/integration/utils.rs b/tests/rgb/integration/utils.rs index 88946dd5..a1b82060 100644 --- a/tests/rgb/integration/utils.rs +++ b/tests/rgb/integration/utils.rs @@ -277,7 +277,7 @@ pub async fn create_new_invoice( let invoice_req = InvoiceRequest { contract_id: contract_id.to_owned(), iface: iface.to_owned(), - amount: amount, + amount, seal, params, }; @@ -370,7 +370,7 @@ pub async fn create_new_invoice_v2( let invoice_req = InvoiceRequest { contract_id: contract_id.to_owned(), iface: iface.to_owned(), - amount: amount, + amount, seal, params, }; diff --git a/tests/rgb/sre/st130.rs b/tests/rgb/sre/st130.rs index 826d01a2..0a333010 100644 --- a/tests/rgb/sre/st130.rs +++ b/tests/rgb/sre/st130.rs @@ -51,10 +51,10 @@ async fn allow_re_issue_rgb_contracts() -> anyhow::Result<()> { // 1. Retrieve metadata let fake_file_name = "fake-name.c15"; - let resp = store(issuer_sk, &fake_file_name, &input, None).await; + let resp = store(issuer_sk, fake_file_name, &input, None).await; assert!(resp.is_ok()); - let resp = retrieve_metadata(issuer_sk, &fake_file_name).await; + let resp = retrieve_metadata(issuer_sk, fake_file_name).await; assert!(resp.is_ok()); // 2. Retrieve contracts From d8898b6be50a9ebd374407ae601e1bf92aa023b2 Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Thu, 29 Jun 2023 06:10:06 -0300 Subject: [PATCH 07/15] feat: add support to re-issue --- .env | 1 + Cargo.lock | 72 ++----------- Cargo.toml | 2 +- docker-compose.yml | 27 +++-- docker/bitmask/Dockerfile | 4 +- docker/bitmask/Dockerfile.ST120 | 39 +++++++ src/bin/bitmaskd.rs | 72 +++++++++++-- src/carbonado.rs | 88 ++++++++++++++-- src/constants.rs | 4 + src/rgb.rs | 173 +++++++++++++++++++++++++++++--- src/rgb/carbonado.rs | 6 +- src/rgb/constants.rs | 2 + src/rgb/contract.rs | 4 +- src/structs.rs | 27 ++++- src/web.rs | 43 +++++++- tests/rgb.rs | 4 + tests/rgb/sre/st130.rs | 124 +++++++++++++++++++++++ tests/web_storage.rs | 2 +- 18 files changed, 581 insertions(+), 113 deletions(-) create mode 100644 docker/bitmask/Dockerfile.ST120 create mode 100644 tests/rgb/sre/st130.rs diff --git a/.env b/.env index a8bb02a5..656b7d41 100644 --- a/.env +++ b/.env @@ -17,6 +17,7 @@ BITCOIN_EXPLORER_API_REGTEST=http://localhost:3000/regtest/api # BITCOIN_ELECTRUM_API_SIGNET=mempool.space:60601 LNDHUB_ENDPOINT=https://lndhubx.bitmask.app # CARBONADO_ENDPOINT=https://qvijq4x0ei.execute-api.us-east-2.amazonaws.com/dev/carbonado +BITMASK_ENDPOINT=http://localhost:7071 CARBONADO_ENDPOINT=http://localhost:7070/carbonado BITCOIN_NETWORK=regtest STRESS_TEST=false diff --git a/Cargo.lock b/Cargo.lock index a3dfa0b7..dc7e1b27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -242,17 +242,6 @@ dependencies = [ "critical-section", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -603,7 +592,7 @@ dependencies = [ "payjoin", "percent-encoding", "postcard 1.0.4", - "pretty_env_logger 0.5.0", + "pretty_env_logger", "psbt", "regex", "reqwest", @@ -769,9 +758,9 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "carbonado" -version = "0.3.0-rc.13" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2510ef3454410abef0be2d8da5b38227530a7ea55c69f666f0179410c61f8858" +checksum = "b1da1a8984d0f5b6dc0f52fce094b537c3f004248992ac1ab829d3f36059a071" dependencies = [ "anyhow", "bao", @@ -782,7 +771,7 @@ dependencies = [ "hex", "log", "nom", - "pretty_env_logger 0.4.0", + "pretty_env_logger", "secp256k1 0.27.0", "serde", "snap", @@ -1166,26 +1155,13 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime 1.3.0", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ - "humantime 2.1.0", + "humantime", "is-terminal", "log", "regex", @@ -1583,15 +1559,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.2.6" @@ -1698,15 +1665,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - [[package]] name = "humantime" version = "2.1.0" @@ -2395,23 +2353,13 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "pretty_env_logger" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" -dependencies = [ - "env_logger 0.7.1", - "log", -] - [[package]] name = "pretty_env_logger" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" dependencies = [ - "env_logger 0.10.0", + "env_logger", "log", ] @@ -2441,12 +2389,6 @@ dependencies = [ "serde_with", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.28" @@ -2571,7 +2513,7 @@ dependencies = [ "bitcoin 0.30.0", "bp-core", "commit_verify", - "env_logger 0.10.0", + "env_logger", "log", "rgb-persist-fs", "rgb-std", diff --git a/Cargo.toml b/Cargo.toml index 09a143af..dd1e15c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ bp-core = "0.10.4" commit_verify = "0.10.3" bp-seals = "0.10.4" indexmap = "1.9.3" -carbonado = "0.3.0-rc.13" +carbonado = "0.3.1" console_error_panic_hook = "0.1.7" # directories = "4.0.1" miniscript_crate = { package = "miniscript", version = "9.0.1", features = [ diff --git a/docker-compose.yml b/docker-compose.yml index 60a7c227..488f2c6f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,10 +3,6 @@ version: "3.7" networks: bmnet: driver: bridge - # ipam: - # config: - # - subnet: 172.21.0.0/24 - # gateway: 172.21.0.1 volumes: node1_data: @@ -32,13 +28,14 @@ services: aliases: - node1 + # Bitmaskd 0.6.0-rc.2 bitmaskd: container_name: bitmaskd - image: bitmask/server:latest + image: bitmask/node:latest platform: linux/amd64 build: context: ./ - dockerfile: ./docker/bitmask/Dockerfile + dockerfile: ./docker/bitmask/Dockerfile.ST120 restart: unless-stopped environment: - BITCOIN_NETWORK=regtest @@ -49,3 +46,21 @@ services: bmnet: aliases: - bitmaskd + + carbonado: + container_name: carbonado + image: carbonado/node:latest + platform: linux/amd64 + build: + context: ./ + dockerfile: ./docker/bitmask/Dockerfile + restart: unless-stopped + environment: + - BITCOIN_NETWORK=regtest + - BITCOIN_EXPLORER_API_REGTEST=http://node1:80/regtest/api + ports: + - 7071:7070 + networks: + bmnet: + aliases: + - bitmaskd diff --git a/docker/bitmask/Dockerfile b/docker/bitmask/Dockerfile index 5915369d..8837718b 100644 --- a/docker/bitmask/Dockerfile +++ b/docker/bitmask/Dockerfile @@ -1,5 +1,5 @@ # Builder -FROM rust:slim AS builder +FROM rust:slim-buster AS builder ARG BUILDER_DIR=/srv/bitmask ARG BUILDER_SRC=/opt/src/bitmask @@ -13,7 +13,7 @@ COPY . . RUN cargo install --locked --features server --path . --root ${BUILDER_DIR} # Runtime -FROM rust:slim AS runtime +FROM rust:slim-buster AS runtime ARG BUILDER_DIR=/srv/bitmask ARG BIN_DIR=/usr/local/bin diff --git a/docker/bitmask/Dockerfile.ST120 b/docker/bitmask/Dockerfile.ST120 new file mode 100644 index 00000000..2649e5e7 --- /dev/null +++ b/docker/bitmask/Dockerfile.ST120 @@ -0,0 +1,39 @@ +# Builder +FROM rust:slim-buster AS builder +ARG BUILDER_DIR=/srv/bitmask +ARG BUILDER_SRC=/opt/src/bitmask +ARG SOURCE_CODE=https://github.com/diba-io/bitmask-core.git +ARG VERSION=c18cba0375dbc4c2f2a5a4fe56401bf3d6d52ce7 + +RUN apt-get update -y && \ + apt-get install -y pkg-config make g++ libssl-dev git + +WORKDIR $BUILDER_DIR +WORKDIR $BUILDER_SRC +RUN git clone $SOURCE_CODE $BUILDER_SRC +RUN git checkout $VERSION +RUN cargo install --locked --features server --path . --root ${BUILDER_DIR} + +# Runtime +FROM rust:slim-buster AS runtime + +ARG BUILDER_DIR=/srv/bitmask +ARG BIN_DIR=/usr/local/bin +ARG DATA_DIR=/tmp/bitmaskd/carbonado/ +ARG USER=bitmask + +RUN apt-get update -y && apt-get install -y iputils-ping telnet \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +RUN adduser --home "${DATA_DIR}" --shell /bin/bash --disabled-login \ + --gecos "${USER} user" ${USER} + +COPY --from=builder --chown=${USER}:${USER} \ + "${BUILDER_DIR}/bin/" "${BIN_DIR}" + +USER ${USER} +VOLUME ${DATA_DIR} +EXPOSE 7070 + +WORKDIR ${BIN_DIR} +ENTRYPOINT ["bitmaskd"] diff --git a/src/bin/bitmaskd.rs b/src/bin/bitmaskd.rs index 054d9cc5..a3d31b57 100644 --- a/src/bin/bitmaskd.rs +++ b/src/bin/bitmaskd.rs @@ -3,6 +3,7 @@ #![cfg(not(target_arch = "wasm32"))] use std::{env, fs::OpenOptions, io::ErrorKind, net::SocketAddr, str::FromStr}; +use amplify::hex::ToHex; use anyhow::Result; use axum::{ body::Bytes, @@ -16,18 +17,19 @@ use axum::{ use bitcoin_30::secp256k1::{ecdh::SharedSecret, PublicKey, SecretKey}; use bitmask_core::{ bitcoin::{decrypt_wallet, get_wallet_data, save_mnemonic, sign_psbt_file}, - carbonado::handle_file, + carbonado::{handle_file, retrieve, retrieve_metadata}, constants::{get_marketplace_seed, get_network, get_udas_utxo, switch_network}, rgb::{ accept_transfer, clear_watcher as rgb_clear_watcher, create_invoice, create_psbt, create_watcher, import as rgb_import, issue_contract, list_contracts, list_interfaces, - list_schemas, transfer_asset, watcher_address, watcher_details as rgb_watcher_details, - watcher_next_address, watcher_next_utxo, watcher_utxo, + list_schemas, reissue_contract, transfer_asset, watcher_address, + watcher_details as rgb_watcher_details, watcher_next_address, watcher_next_utxo, + watcher_utxo, }, structs::{ - AcceptRequest, ImportRequest, InvoiceRequest, IssueAssetRequest, IssueRequest, MediaInfo, - PsbtRequest, RgbTransferRequest, SecretString, SelfIssueRequest, SignPsbtRequest, - WatcherRequest, + AcceptRequest, FileMetadata, ImportRequest, InvoiceRequest, IssueAssetRequest, + IssueRequest, MediaInfo, PsbtRequest, ReIssueRequest, RgbTransferRequest, SecretString, + SelfIssueRequest, SignPsbtRequest, WatcherRequest, }, }; use carbonado::file; @@ -37,11 +39,25 @@ use serde::{Deserialize, Serialize}; use tokio::fs; use tower_http::cors::CorsLayer; -async fn issue(Json(issue): Json) -> Result { - info!("POST /issue {issue:?}"); +async fn issue( + TypedHeader(auth): TypedHeader>, + Json(request): Json, +) -> Result { + info!("POST /issue {request:?}"); + + let nostr_hex_sk = auth.token(); + let issue_res = issue_contract(nostr_hex_sk, request).await?; + Ok((StatusCode::OK, Json(issue_res))) +} - let issue_res = issue_contract(&issue.sk, issue.request).await?; +async fn reissue( + TypedHeader(auth): TypedHeader>, + Json(request): Json, +) -> Result { + info!("POST /reissue {request:?}"); + let nostr_hex_sk = auth.token(); + let issue_res = reissue_contract(&nostr_hex_sk, request).await?; Ok((StatusCode::OK, Json(issue_res))) } @@ -352,6 +368,42 @@ async fn co_retrieve( } } +async fn co_metadata( + Path((pk, name)): Path<(String, String)>, +) -> Result { + info!("GET /carbonado/{pk}/{name}/metadata"); + + let filepath = &handle_file(&pk, &name, 0).await?; + let mut metadata = FileMetadata::default(); + match OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&filepath) + { + Ok(file) => { + let present_header = match carbonado::file::Header::try_from(&file) { + Ok(header) => header, + _ => return Ok((StatusCode::OK, Json(metadata))), + }; + + metadata.filename = present_header.file_name(); + metadata.metadata = present_header.metadata.unwrap_or_default(); + } + Err(err) => match err.kind() { + ErrorKind::NotFound => { + fs::write(&filepath, &vec![]).await?; + } + _ => { + error!("error in POST /carbonado/{pk}/{name}: {err}"); + return Err(err.into()); + } + }, + } + + Ok((StatusCode::OK, Json(metadata))) +} + async fn status() -> Result { let cc = CacheControl::new().with_no_cache(); @@ -380,6 +432,7 @@ async fn main() -> Result<()> { let app = Router::new() .route("/issue", post(issue)) + .route("/reissue", post(reissue)) .route("/selfissue", post(self_issue)) .route("/invoice", post(invoice)) // .route("/psbt", post(psbt)) @@ -405,6 +458,7 @@ async fn main() -> Result<()> { .route("/carbonado/status", get(status)) .route("/carbonado/:pk/:name", post(co_store)) .route("/carbonado/:pk/:name", get(co_retrieve)) + .route("/carbonado/:pk/:name/metadata", get(co_metadata)) .layer(CorsLayer::permissive()); let network = get_network().await; diff --git a/src/carbonado.rs b/src/carbonado.rs index d1fc2b19..079313db 100644 --- a/src/carbonado.rs +++ b/src/carbonado.rs @@ -13,6 +13,7 @@ use percent_encoding::utf8_percent_encode; pub mod constants; +use crate::structs::FileMetadata; #[cfg(not(feature = "server"))] use crate::{ carbonado::constants::FORM, @@ -20,14 +21,20 @@ use crate::{ }; #[cfg(not(feature = "server"))] -pub async fn store(sk: &str, name: &str, input: &[u8]) -> Result<()> { +pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option>) -> Result<()> { let level = 15; let sk = hex::decode(sk)?; let secret_key = SecretKey::from_slice(&sk)?; let public_key = PublicKey::from_secret_key_global(&secret_key); let pk = public_key.serialize(); let pk_hex = hex::encode(pk); - let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level)?; + + let mut meta: Option<[u8; 8]> = None; + if let Some(metadata) = metadata { + meta = Some(metadata.try_into().expect("invalid metadata size")); + } + + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, meta)?; let endpoint = CARBONADO_ENDPOINT.read().await.to_string(); let name = utf8_percent_encode(name, FORM); let network = NETWORK.read().await.to_string(); @@ -58,20 +65,61 @@ pub async fn store(sk: &str, name: &str, input: &[u8]) -> Result<()> { } #[cfg(feature = "server")] -pub async fn store(sk: &str, name: &str, input: &[u8]) -> Result<()> { +pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option>) -> Result<()> { let level = 15; let sk = hex::decode(sk)?; let secret_key = SecretKey::from_slice(&sk)?; let public_key = PublicKey::from_secret_key_global(&secret_key); let pk = public_key.serialize(); let pk_hex = hex::encode(pk); - let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level)?; + + let mut meta: Option<[u8; 8]> = None; + if let Some(metadata) = metadata { + meta = Some(metadata.try_into().expect("invalid metadata size")); + } + + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, meta)?; let filepath = handle_file(&pk_hex, name, body.len()).await?; fs::write(filepath, body).await?; Ok(()) } +#[cfg(not(feature = "server"))] +pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { + let sk = hex::decode(sk)?; + let secret_key = SecretKey::from_slice(&sk)?; + let public_key = PublicKey::from_secret_key_global(&secret_key); + let pk = public_key.to_hex(); + + let endpoint = CARBONADO_ENDPOINT.read().await.to_string(); + let name = utf8_percent_encode(name, FORM); + let network = NETWORK.read().await.to_string(); + let url = format!("{endpoint}/{pk}/{network}-{name}/metadata"); + let client = reqwest::Client::new(); + let response = client + .get(&url) + .header("Accept", "application/octet-stream") + .header("Cache-Control", "no-cache") + .send() + .await + .context(format!("Error sending JSON POST request to {url}"))?; + + let status_code = response.status().as_u16(); + + if status_code != 200 { + let response_text = response.text().await.context(format!( + "Error in parsing server response for POST JSON request to {url}" + ))?; + return Err(anyhow!( + "Error in retrieving carbonado file, status: {status_code} error: {response_text}" + )); + } + + let result = response.json::().await?; + Ok(result) +} + #[cfg(not(feature = "server"))] pub async fn retrieve(sk: &str, name: &str) -> Result> { let sk = hex::decode(sk)?; @@ -107,11 +155,38 @@ pub async fn retrieve(sk: &str, name: &str) -> Result> { if encoded.is_empty() { Ok(Vec::new()) } else { - let (_header, decoded) = carbonado::file::decode(&sk, &encoded)?; + let (_, decoded) = carbonado::file::decode(&sk, &encoded)?; Ok(decoded) } } +#[cfg(feature = "server")] +pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { + use crate::constants::NETWORK; + + let sk = hex::decode(sk)?; + let secret_key = SecretKey::from_slice(&sk)?; + let public_key = PublicKey::from_secret_key_global(&secret_key); + let pk = public_key.to_hex(); + + let network = NETWORK.read().await.to_string(); + let mut final_name = name.to_string(); + if !name.contains(&network) { + final_name = format!("{network}-{name}"); + } + + let filepath = handle_file(&pk, &final_name, 0).await?; + let bytes = fs::read(filepath).await?; + + let (header, _) = carbonado::file::decode(&sk, &bytes)?; + let result = FileMetadata { + filename: header.file_name(), + metadata: header.metadata.unwrap_or_default(), + }; + + Ok(result) +} + #[cfg(feature = "server")] pub async fn retrieve(sk: &str, name: &str) -> Result> { use crate::constants::NETWORK; @@ -133,7 +208,8 @@ pub async fn retrieve(sk: &str, name: &str) -> Result> { if bytes.is_empty() { Ok(Vec::new()) } else { - let (_header, decoded) = carbonado::file::decode(&sk, &bytes)?; + let (_, decoded) = carbonado::file::decode(&sk, &bytes)?; + Ok(decoded) } } diff --git a/src/constants.rs b/src/constants.rs index af9392b0..42532bc4 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -125,6 +125,10 @@ pub async fn switch_network(network_str: &str) -> Result<()> { pub static LNDHUB_ENDPOINT: Lazy> = Lazy::new(|| RwLock::new(dot_env("LNDHUB_ENDPOINT"))); +// bitmask node +pub static BITMASK_ENDPOINT: Lazy> = + Lazy::new(|| RwLock::new(dot_env("BITMASK_ENDPOINT"))); + // carbonado pub static CARBONADO_ENDPOINT: Lazy> = Lazy::new(|| RwLock::new(dot_env("CARBONADO_ENDPOINT"))); diff --git a/src/rgb.rs b/src/rgb.rs index 4af13767..8f545556 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -1,5 +1,3 @@ -use std::{collections::BTreeMap, str::FromStr}; - use ::psbt::serialize::Serialize; use amplify::{confinement::U16, hex::ToHex}; use anyhow::{anyhow, Result}; @@ -12,6 +10,7 @@ use rgbstd::{ contract::ContractId, persistence::{Stash, Stock}, }; +use std::{collections::BTreeMap, str::FromStr}; use strict_encoding::StrictSerialize; pub mod accept; @@ -46,12 +45,13 @@ use crate::{ wallet::list_allocations, }, structs::{ - AcceptRequest, AcceptResponse, AssetType, ContractResponse, ContractsResponse, - ImportRequest, InterfaceDetail, InterfacesResponse, InvoiceRequest, InvoiceResponse, - IssueRequest, IssueResponse, NextAddressResponse, NextUtxoResponse, NextUtxosResponse, - PsbtRequest, PsbtResponse, RgbTransferRequest, RgbTransferResponse, SchemaDetail, - SchemasResponse, WatcherDetailResponse, WatcherRequest, WatcherResponse, - WatcherUtxoResponse, + AcceptRequest, AcceptResponse, AssetType, ContractMetadata, ContractResponse, + ContractsResponse, ImportRequest, InterfaceDetail, InterfacesResponse, InvoiceRequest, + InvoiceResponse, IssueMetaRequest, IssueMetadata, IssueRequest, IssueResponse, + NewCollectible, NextAddressResponse, NextUtxoResponse, NextUtxosResponse, PsbtRequest, + PsbtResponse, ReIssueRequest, ReIssueResponse, RgbTransferRequest, RgbTransferResponse, + SchemaDetail, SchemasResponse, UDADetail, WatcherDetailResponse, WatcherRequest, + WatcherResponse, WatcherUtxoResponse, }, }; @@ -72,8 +72,10 @@ use self::{ }; /// RGB Operations -#[allow(clippy::too_many_arguments)] pub async fn issue_contract(sk: &str, request: IssueRequest) -> Result { + let mut stock = retrieve_stock(sk, ASSETS_STOCK).await?; + let mut rgb_account = retrieve_wallets(sk, ASSETS_WALLETS).await?; + let IssueRequest { ticker, name, @@ -84,8 +86,6 @@ pub async fn issue_contract(sk: &str, request: IssueRequest) -> Result Result Result Result { + let mut stock = Stock::default().clone(); + let mut rgb_account = retrieve_wallets(sk, ASSETS_WALLETS).await?; + + // Prefetch + let mut resolver = ExplorerResolver { + explorer_url: BITCOIN_EXPLORER_API.read().await.to_string(), + ..Default::default() + }; + + let mut reissue_resp = vec![]; + for contract in request.contracts { + let ContractResponse { + ticker, + name, + description, + supply, + contract_id: _, + iimpl_id: _, + iface, + precision, + balance: _, + allocations, + contract: _, + genesis: _, + meta: contract_meta, + } = contract; + + let seals: Vec = allocations + .into_iter() + .map(|alloc| format!("tapret1st:{}", alloc.utxo)) + .collect(); + let seal = seals.first().unwrap().to_owned(); + + let mut meta = None; + if let Some(contract_meta) = contract_meta { + meta = Some(match contract_meta.meta() { + ContractMetadata::UDA(uda) => IssueMetaRequest(IssueMetadata::UDA(uda.media)), + ContractMetadata::Collectible(colectibles) => { + let mut items = vec![]; + for collectible_item in colectibles { + let UDADetail { + ticker, + name, + token_index: _, + description, + balance: _, + media, + allocations: _, + } = collectible_item; + + let new_item = NewCollectible { + ticker, + name, + description, + media, + }; + + items.push(new_item); + } + + IssueMetaRequest(IssueMetadata::Collectible(items)) + } + }) + } + + let network = get_network().await; + let wallet = rgb_account.wallets.get("default"); + let mut wallet = match wallet { + Some(wallet) => { + let mut fetch_wallet = wallet.to_owned(); + for contract_type in [AssetType::RGB20, AssetType::RGB21] { + prefetch_resolver_utxos(contract_type as u32, &mut fetch_wallet, &mut resolver) + .await; + } + + Some(fetch_wallet) + } + _ => None, + }; + + let contract = create_contract( + &ticker, + &name, + &description, + precision, + supply, + &iface, + &seal, + &network, + meta, + &mut resolver, + &mut stock, + )?; + + let ContractResponse { + contract_id, + iimpl_id, + iface, + ticker, + name, + description, + supply, + precision: _, + balance: _, + allocations: _, + contract, + genesis, + meta, + } = extract_contract_by_id( + contract.contract_id(), + &mut stock, + &mut resolver, + &mut wallet, + )?; + + if let Some(wallet) = wallet { + rgb_account + .wallets + .insert(RGB_DEFAULT_NAME.to_string(), wallet); + }; + + reissue_resp.push(IssueResponse { + contract_id, + iface, + iimpl_id, + ticker, + name, + description, + supply, + precision, + contract, + genesis, + issue_utxo: seal.replace("tapret1st:", ""), + meta, + }); + } + + store_stock(sk, ASSETS_STOCK, &stock).await?; + store_wallets(sk, ASSETS_WALLETS, &rgb_account).await?; + + Ok(ReIssueResponse { + contracts: reissue_resp, + }) +} + pub async fn create_invoice(sk: &str, request: InvoiceRequest) -> Result { let InvoiceRequest { contract_id, diff --git a/src/rgb/carbonado.rs b/src/rgb/carbonado.rs index 47d35d4f..56f2ed9e 100644 --- a/src/rgb/carbonado.rs +++ b/src/rgb/carbonado.rs @@ -5,12 +5,12 @@ use rgbstd::persistence::Stock; use strict_encoding::{StrictDeserialize, StrictSerialize}; use crate::carbonado::{retrieve, store}; +use crate::rgb::constants::RGB_STRICT_TYPE_VERSION; use crate::rgb::structs::RgbAccount; pub async fn store_stock(sk: &str, name: &str, stock: &Stock) -> Result<()> { let data = stock.to_strict_serialized::()?; - - store(sk, name, &data).await + store(sk, name, &data, Some(RGB_STRICT_TYPE_VERSION.to_vec())).await } pub async fn retrieve_stock(sk: &str, name: &str) -> Result { @@ -27,7 +27,7 @@ pub async fn retrieve_stock(sk: &str, name: &str) -> Result { pub async fn store_wallets(sk: &str, name: &str, rgb_wallets: &RgbAccount) -> Result<()> { let data = to_allocvec(rgb_wallets)?; - store(sk, name, &data).await + store(sk, name, &data, Some(RGB_STRICT_TYPE_VERSION.to_vec())).await } pub async fn retrieve_wallets(sk: &str, name: &str) -> Result { diff --git a/src/rgb/constants.rs b/src/rgb/constants.rs index 43481d06..971a031b 100644 --- a/src/rgb/constants.rs +++ b/src/rgb/constants.rs @@ -2,3 +2,5 @@ pub const LIB_NAME_BITMASK: &str = "bitmask"; pub const RGB_CHANGE_INDEX: &str = "0"; pub const RGB_PSBT_TAPRET: &str = "TAPRET"; pub const RGB_DEFAULT_NAME: &str = "default"; +pub const RGB_OLDEST_VERSION: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; +pub const RGB_STRICT_TYPE_VERSION: [u8; 8] = [b'r', b'g', b'b', b's', b't', b'1', b'3', b'0']; diff --git a/src/rgb/contract.rs b/src/rgb/contract.rs index 3b35d46b..392ac22a 100644 --- a/src/rgb/contract.rs +++ b/src/rgb/contract.rs @@ -68,7 +68,7 @@ where let mut ticker = String::new(); let mut name = String::new(); - let mut precision = 0; + let mut precision: u8 = 0; let mut description = String::new(); let ty: FieldName = FieldName::from("spec"); @@ -95,7 +95,7 @@ where } if let Some(StrictVal::Enum(en)) = fields.get(&FieldName::from("precision")) { let val = en.unwrap_ord(); - precision = val as u64; + precision = val; } }; } diff --git a/src/structs.rs b/src/structs.rs index 2bc14a85..6ea968bc 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -132,6 +132,13 @@ pub struct SelfIssueRequest { pub meta: Option, } +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct ReIssueRequest { + /// previous contracts + pub contracts: Vec, +} + #[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct IssueMetaRequest(pub IssueMetadata); @@ -232,6 +239,12 @@ pub struct GenesisFormats { pub armored: String, } +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct ReIssueResponse { + pub contracts: Vec, +} + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub enum AssetType { @@ -272,7 +285,7 @@ pub struct ContractResponse { /// Amount of the asset pub supply: u64, /// Precision of the asset - pub precision: u64, + pub precision: u8, /// The user contract balance pub balance: u64, /// The contract allocations @@ -293,6 +306,10 @@ impl ContractMeta { pub fn with(metadata: ContractMetadata) -> Self { ContractMeta(metadata) } + + pub fn meta(self) -> ContractMetadata { + self.0 + } } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -536,6 +553,7 @@ pub struct AllocationDetail { /// My Allocation? pub is_mine: bool, /// Allocation spent? + #[serde(skip)] pub is_spent: bool, } @@ -640,3 +658,10 @@ pub struct ExportRequestMini { /// ContractId of the asset to export FROM the node pub asset: String, } + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct FileMetadata { + pub filename: String, + pub metadata: [u8; 8], +} diff --git a/src/web.rs b/src/web.rs index 577cb214..404fbad6 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,6 +1,6 @@ use crate::structs::{ - AcceptRequest, ImportRequest, InvoiceRequest, IssueRequest, PsbtRequest, RgbTransferRequest, - SecretString, SignPsbtRequest, WatcherRequest, + AcceptRequest, ImportRequest, InvoiceRequest, IssueRequest, PsbtRequest, ReIssueRequest, + RgbTransferRequest, SecretString, SignPsbtRequest, WatcherRequest, }; // use crate::{carbonado, lightning, rgb}; @@ -320,6 +320,22 @@ pub mod rgb { }) } + #[allow(clippy::too_many_arguments)] + #[wasm_bindgen] + pub fn reissue_contract(nostr_hex_sk: String, request: JsValue) -> Promise { + set_panic_hook(); + + future_to_promise(async move { + let req: ReIssueRequest = serde_wasm_bindgen::from_value(request).unwrap(); + match crate::rgb::reissue_contract(&nostr_hex_sk, req).await { + Ok(result) => Ok(JsValue::from_string( + serde_json::to_string(&result).unwrap(), + )), + Err(err) => Err(JsValue::from_string(err.to_string())), + } + }) + } + #[wasm_bindgen] pub fn rgb_create_invoice(nostr_hex_sk: String, request: JsValue) -> Promise { set_panic_hook(); @@ -658,11 +674,16 @@ pub mod carbonado { use super::*; #[wasm_bindgen] - pub fn store(secret_key: String, name: String, data: Vec) -> Promise { + pub fn store( + secret_key: String, + name: String, + data: Vec, + metadata: Option>, + ) -> Promise { set_panic_hook(); future_to_promise(async move { - match crate::carbonado::store(&secret_key, &name, &data).await { + match crate::carbonado::store(&secret_key, &name, &data, metadata).await { Ok(result) => Ok(JsValue::from_string( serde_json::to_string(&result).unwrap(), )), @@ -689,6 +710,20 @@ pub mod carbonado { }) } + #[wasm_bindgen] + pub fn retrieve_metadata(secret_key: String, name: String) -> Promise { + set_panic_hook(); + + future_to_promise(async move { + match crate::carbonado::retrieve_metadata(&secret_key, &name).await { + Ok(result) => Ok(JsValue::from_string( + serde_json::to_string(&result).unwrap(), + )), + Err(err) => Err(JsValue::from_string(err.to_string())), + } + }) + } + #[wasm_bindgen] pub fn encode_hex(bytes: Vec) -> String { set_panic_hook(); diff --git a/tests/rgb.rs b/tests/rgb.rs index f296722b..464ffcf2 100644 --- a/tests/rgb.rs +++ b/tests/rgb.rs @@ -28,4 +28,8 @@ mod rgb { mod imports; mod std; } + + mod sre { + mod st130; + } } diff --git a/tests/rgb/sre/st130.rs b/tests/rgb/sre/st130.rs new file mode 100644 index 00000000..826d01a2 --- /dev/null +++ b/tests/rgb/sre/st130.rs @@ -0,0 +1,124 @@ +#![cfg(not(target_arch = "wasm32"))] +use crate::rgb::integration::utils::ISSUER_MNEMONIC; +use anyhow::{anyhow, Context}; +use bitmask_core::carbonado::{retrieve_metadata, store}; +use bitmask_core::structs::WatcherRequest; +use bitmask_core::{ + bitcoin::save_mnemonic, + carbonado::constants::FORM, + constants::{storage_keys::ASSETS_STOCK, BITMASK_ENDPOINT, NETWORK}, + rgb::{constants::RGB_OLDEST_VERSION, reissue_contract}, + structs::{ContractsResponse, ReIssueRequest, SecretString}, +}; +use hex::FromHex; +use nostr_sdk::key::{PublicKey, SecretKey}; +use percent_encoding::utf8_percent_encode; +use reqwest::Client; + +#[tokio::test] +#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.3.0)"] +async fn allow_re_issue_rgb_contracts() -> anyhow::Result<()> { + let bitmask_endpoint = BITMASK_ENDPOINT.read().await.to_string(); + let issuer_keys = save_mnemonic( + &SecretString(ISSUER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + + // 0. Create Watcher + let issuer_sk = &issuer_keys.private.nostr_prv; + let client = Client::new(); + let endpoint = format!("{bitmask_endpoint}/watcher"); + let watch_req = WatcherRequest { + name: "default".to_string(), + xpub: issuer_keys.public.watcher_xpub.clone(), + force: true, + }; + let resp = client + .post(&endpoint) + .json(&watch_req) + .bearer_auth(issuer_sk) + .send() + .await; + assert!(resp.is_ok()); + + // 0. Prepare Data Test + let file_name = ASSETS_STOCK.to_string(); + let input = Vec::::from_hex(STOCK_ST_120)?; + + let resp = store_in_server(issuer_sk, &file_name, &input, None).await; + assert!(resp.is_ok()); + + // 1. Retrieve metadata + let fake_file_name = "fake-name.c15"; + let resp = store(issuer_sk, &fake_file_name, &input, None).await; + assert!(resp.is_ok()); + + let resp = retrieve_metadata(issuer_sk, &fake_file_name).await; + assert!(resp.is_ok()); + + // 2. Retrieve contracts + let file_header = resp?; + if file_header.metadata == RGB_OLDEST_VERSION { + let endpoint = format!("{bitmask_endpoint}/contracts"); + + let result = client.get(&endpoint).bearer_auth(issuer_sk).send().await?; + + let resp = result.json::().await?; + let reissue_req = ReIssueRequest { + contracts: resp.contracts, + }; + + // 2. ReIssue contracts + let reissue_resp = reissue_contract(issuer_sk, reissue_req).await; + assert!(reissue_resp.is_ok()); + } + + Ok(()) +} + +async fn store_in_server( + sk: &str, + name: &str, + input: &[u8], + metadata: Option<[u8; 8]>, +) -> anyhow::Result<()> { + let level = 15; + let sk = hex::decode(sk)?; + let secret_key = SecretKey::from_slice(&sk)?; + let public_key = PublicKey::from_secret_key_global(&secret_key); + let pk = public_key.serialize(); + let pk_hex = hex::encode(pk); + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, metadata)?; + let endpoint = BITMASK_ENDPOINT.read().await.to_string(); + let name = utf8_percent_encode(name, FORM); + let network = NETWORK.read().await.to_string(); + let url = format!("{endpoint}/carbonado/{pk_hex}/{network}-{name}"); + let client = reqwest::Client::new(); + let response = client + .post(&url) + .body(body) + .header("Content-Type", "application/octet-stream") + .header("Cache-Control", "no-cache") + .send() + .await + .context(format!("Error sending JSON POST request to {url}"))?; + + let status_code = response.status().as_u16(); + + if status_code != 200 { + let response_text = response.text().await.context(format!( + "Error in parsing server response for POST JSON request to {url}" + ))?; + + println!("{}", url); + + Err(anyhow!( + "Error in storing carbonado file, status: {status_code} error: {response_text}" + )) + } else { + Ok(()) + } +} + +const STOCK_ST_120: &str = "02d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd000000030300cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e4300100d007b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100d107b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010001d007010800c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b103030001000100d00701000100d1070100010001d0070100ffff000001d007c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10001d0070100ffff01d0070100ffff0037000017acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd010b524742436f6e7472616374044e616d65050198db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d81bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0107426974636f696e0554784f757406020576616c7565cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00c7363726970745075626b65794a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba1df1d11643dd30bf0b583883dfa61289186277ace4ad075e3c67ac0b83802eaa01035374640a486578446563436170730310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e4623bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0107426974636f696e095369675363726970740501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c3027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000403719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac600040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e38fd0b174ca8528da005d978de7dd5a2a763bb67e42ca25b935edf451344229e01035374640a416c706861536d616c6c031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e00050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d104693e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100000000000000000ffff0000000000004a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba0107426974636f696e0c5363726970745075626b65790501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c52740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560107426974636f696e084f7574706f696e7406020474786964b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab404766f7574fd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d5577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b000360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377f55accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b01035374640e41736369695072696e7461626c65035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e58a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066170000445cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80600085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b0100000000000000080000000000000060fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec010b524742436f6e74726163740b41737365744e616d696e670603067469636b657292e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506046e616d6517acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd0764657461696c733719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac661cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a25510000161dac6b5168357edbd878765f0382f79d864835c01c7e3a0d0747a235404c3ba010353746408416c7068614e756d033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a66ff6ddb2093d3e48033bbd707da2588df6a93d25b7d419c0592cadb31e8a2da0107426974636f696e02547806040776657273696f6e6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e8863206696e70757473e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba076f75747075747376ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f3086c6f636b54696d656f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e886320107426974636f696e055478566572050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066176c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110000086f0cbcc3130d8fdbd168f60ebb2477f344d85659ca1fc56d84b235072b67c74501035374640e416c7068614e756d4c6f64617368033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a6f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b0107426974636f696e084c6f636b54696d650501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253175b7c2e75f4dbfc3728201bc72c62986a08f2734cb3e50f32e6aad2f21343f5a010353746409416c70686143617073031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a76ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f300081bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0000000000000000ffffffffffffffff8a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffff0000000000008df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40107426974636f696e045478496e06040a707265764f757470757452740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560973696753637269707423bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0873657175656e6365bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff7077769746e657373bd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff791281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469010b524742436f6e74726163740744657461696c730501d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f92e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506010b524742436f6e7472616374065469636b657205015cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80698db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d800085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b01000000000000002800000000000000a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffffffffffffffffa788a36d6e35c945b224869165f2844711784f55b6b484b2f21f35397170ad8401035374640255340310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fae6894c8d85e1f4b6e7a31dabf56f6a09c1f423f6ce5fd49ea56bc025cb4f22301035374640c416c7068614e756d44617368033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7ab0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a5400073027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9962000b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010b524742436f6e74726163741152696361726469616e436f6e747261637405013e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd8989010b524742436f6e747261637412446976697369626c654173736574537065630602066e616d696e6760fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec09707265636973696f6ec554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab40107426974636f696e04547869640501b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54b9ef64121db10df182d4df713abb2b2e97a73f8f9c116f81f54577c3e0bf015b010353746403446563030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80010b524742436f6e74726163740f50726f6f664f6652657365727665730602047574786fb1e43bec82e3821b2d7ccee89a7d213da8b77eea0518bcfa4f6d6f8dfe0296de0570726f6f668a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caaebbd8604f99b5c9047de07d559069a286d27c94143106e2f5eae266ae44f7168701035374640c416c706861436170734e756d0324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5abd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff70107426974636f696e075769746e6573730501f5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c548bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff70107426974636f696e055365714e6f0501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5010b524742436f6e747261637409507265636973696f6e03130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f12c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b1000000cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e430010b524742436f6e74726163740954696d657374616d70050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c752606617cb958efe9c6d304f13222e2a4907124e86e7ea1c5a74e24c3e2235f6c4d2a9a501035374640b486578446563536d616c6c0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00107426974636f696e045361747305016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b11d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100100000000000000ff00000000000000e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000004e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba00088df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40000000000000000fffffffffffffffff27e112e62134308df24f66cd6a133e473d72977d65f49467f1fd8a4d92a13c7010353746404426f6f6c03020566616c736500047472756501f41f2a6324dcada5162bb3034f7c2a19ad40b9124fb467e44c5a0d772c430d8e010353746405416c7068610334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7af5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c5480008a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe0000000000000000fffffffffffffffff82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c0107426974636f696e0b53637269707442797465730501a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fefd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d0107426974636f696e04566f75740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253100015650fb29bac1c7616f976727b1e81234887ad96e7056f5a3cc99e4a8378b31480c00035247420300d0d007000000010004d0075650fb29bac1c7616f976727b1e81234887ad96e7056f5a3cc99e4a8378b3148000001dd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce900d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bddd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce90303000763726561746564d0070473706563d107057465726d7301d0070b62656e65666963696172790001d007085472616e7366657200dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d4000000050300cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001003408b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd898901003508b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae37798610700100360806df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c01003808869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f60100013408025d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa81000c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b105030001000100340801000100350801000100360800000100380800000100013408010001000000013408c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b100013408010001000134080100010000580000017447c77d2367544618e2aaf4e680659b9df075544650b5a4bbab699ea258c800040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d651da55835280aba3b02d1b5d02fc3fc47c267e8ed85554b0e7d13beed5c132b30065602cf1069e5dcfccabc7fd98ca570ce4eb972bddfb8c63633483dd519c19d00085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b0100000000000000400000000000000006df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c0105524742323109546f6b656e44617461060805696e646578d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d7664067469636b6572d669d8d150ff6a2e7486568b066e2fb43e4efe6aab93d103d8f559d14a6ccd15046e616d65017447c77d2367544618e2aaf4e680659b9df075544650b5a4bbab699ea258c80764657461696c73181998eeb65f373753d54b4983424050c38cb464d587d6a3741a13c69abfdc1007707265766965774cc79dab63f53b172bd53af42d3c1b9e36fdc5ba19ec625dcf99cf9ee6d23178056d65646961ba7da437dd2009266764a53302be280bec57a35edea906c42185c96e1a1d4e840b6174746163686d656e74730f1b2b5d80322340d1064fcfc7b82c98002836666b576b1eb7baf1a2d2756cff0872657365727665730c90d2700887419382cbcbd28c78d7c1b112602e4438551c3ca58ae68a975cbc0718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7010552474232310949737375654d65746106010872657365727665734d09d713e21e9bbabd91ffe3ac096102dcfe3ed8994f7089158532a139a024bb09317e1367c0edbbfffb675b5329d6554a0ec62580c5e5a5215af318270a88b3010552474232310d4f776e65644672616374696f6e05016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110c90d2700887419382cbcbd28c78d7c1b112602e4438551c3ca58ae68a975cbc00040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65affcae68cd21c376584c7b4a68de738dfad6386a7d6d3a7bbb348227976d14f80f1b2b5d80322340d1064fcfc7b82c98002836666b576b1eb7baf1a2d2756cff000a0001a84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e20000000000000000140000000000000017acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd010b524742436f6e7472616374044e616d65050198db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d8181998eeb65f373753d54b4983424050c38cb464d587d6a3741a13c69abfdc1000040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65b360cb3d1a1ce2559dd5cc11d2b3164467211559b80a239b16d081f394fa5b531bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0107426974636f696e0554784f757406020576616c7565cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00c7363726970745075626b65794a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba1da55835280aba3b02d1b5d02fc3fc47c267e8ed85554b0e7d13beed5c132b3000050117acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd1df1d11643dd30bf0b583883dfa61289186277ace4ad075e3c67ac0b83802eaa01035374640a486578446563436170730310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e4623bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0107426974636f696e095369675363726970740501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c3027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000403719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac600040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e38fd0b174ca8528da005d978de7dd5a2a763bb67e42ca25b935edf451344229e01035374640a416c706861536d616c6c031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e00050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d104693e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100000000000000000ffff000000000000470ad9ae9cbc8fa7428330b0c0a4fb32d1f9fc30a94eaa4b3c41145b849a56e9000501a84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e2497c7eb9391a079a38d92afdde2e4eec03a9a37987201d5ab5b14d45c17b250d010552474232310d456e67726176696e67446174610602096170706c696564546fd3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d766407636f6e74656e747b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da24a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba0107426974636f696e0c5363726970745075626b65790501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c4cc79dab63f53b172bd53af42d3c1b9e36fdc5ba19ec625dcf99cf9ee6d2317800040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d656022af4d5e00c75978b1d60421997e0b227b395dce5e52da8e030b6ae9174a444d09d713e21e9bbabd91ffe3ac096102dcfe3ed8994f7089158532a139a024bb0009ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc800000000000000000ffff0000000000004f46dce8279430081e45f623d0d618ed7f52efb553bc241b0d2ae7ec601c1a5c01055247423231094d6564696154797065060304747970655538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa0773756274797065b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b90763686172736574b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b952740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560107426974636f696e084f7574706f696e7406020474786964b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab404766f7574fd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d5538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa010552474232310c4d656469615265674e616d650501065602cf1069e5dcfccabc7fd98ca570ce4eb972bddfb8c63633483dd519c19d5577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b000360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377f55accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b01035374640e41736369695072696e7461626c65035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e58a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066170000445cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80600085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b010000000000000008000000000000005d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa810010552474232310a416c6c6f636174696f6e0502d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d766409317e1367c0edbbfffb675b5329d6554a0ec62580c5e5a5215af318270a88b36022af4d5e00c75978b1d60421997e0b227b395dce5e52da8e030b6ae9174a440005017b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da260fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec010b524742436f6e74726163740b41737365744e616d696e670603067469636b657292e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506046e616d6517acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd0764657461696c733719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac661cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a25510000161dac6b5168357edbd878765f0382f79d864835c01c7e3a0d0747a235404c3ba010353746408416c7068614e756d033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a66ff6ddb2093d3e48033bbd707da2588df6a93d25b7d419c0592cadb31e8a2da0107426974636f696e02547806040776657273696f6e6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e8863206696e70757473e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba076f75747075747376ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f3086c6f636b54696d656f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b695eb06afff78803151c5c7c1620648f52dca30526ce3ec3fea1ad7fcab75a8a000855accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b010000000000000014000000000000006963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e886320107426974636f696e055478566572050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066176c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110000086f0cbcc3130d8fdbd168f60ebb2477f344d85659ca1fc56d84b235072b67c74501035374640e416c7068614e756d4c6f64617368033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a6f23e8a03955547d9bd76db47bb7e5eea3792d5f8f223c790cc2b5eed658c09f0005015538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa6f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b0107426974636f696e084c6f636b54696d650501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253175b7c2e75f4dbfc3728201bc72c62986a08f2734cb3e50f32e6aad2f21343f5a010353746409416c70686143617073031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a76ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f300081bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0000000000000000ffffffffffffffff7b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da2010552474232310d456d6265646465644d65646961060204747970654f46dce8279430081e45f623d0d618ed7f52efb553bc241b0d2ae7ec601c1a5c04646174618a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f6010552474232310e4174746163686d656e74547970650602026964cd2a948954a0dc1dd1a4e04145245638af3f544c133c68bf1af183cb3346668a046e616d659819b0f8b92eac0f19205791b5016c23f78f78560bb47d74e266a9c24b0cf33e8a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffff0000000000008aa05647e0f89c231194d76e4f776ef7d3255028c484cb63a8a68f7d0251695e00050192e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be8429835068df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40107426974636f696e045478496e06040a707265764f757470757452740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560973696753637269707423bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0873657175656e6365bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff7077769746e657373bd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff79048212cad2ed6e09a3e853c904f71889286e17ec23d0a3b6326ecee721b7b9901055247423231054572726f720308106672616374696f6e4f766572666c6f77010e6e6f6e457175616c56616c756573020c696e76616c696450726f6f660314696e73756666696369656e7452657365727665730415697373756545786365656473416c6c6f77616e636506126e6f6e4672616374696f6e616c546f6b656e07126e6f6e456e6772617661626c65546f6b656e0815696e76616c69644174746163686d656e74547970650991281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469010b524742436f6e74726163740744657461696c730501d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f92e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506010b524742436f6e7472616374065469636b657205015cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb8069819b0f8b92eac0f19205791b5016c23f78f78560bb47d74e266a9c24b0cf33e010552474232310e4174746163686d656e744e616d650501695eb06afff78803151c5c7c1620648f52dca30526ce3ec3fea1ad7fcab75a8a98db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d800085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b01000000000000002800000000000000a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffffffffffffffffa788a36d6e35c945b224869165f2844711784f55b6b484b2f21f35397170ad8401035374640255340310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e2010552474232310a4174746163686d656e7406020474797065869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f606646967657374b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54ae6894c8d85e1f4b6e7a31dabf56f6a09c1f423f6ce5fd49ea56bc025cb4f22301035374640c416c7068614e756d44617368033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7aaffcae68cd21c376584c7b4a68de738dfad6386a7d6d3a7bbb348227976d14f8000501ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a5400073027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9962000b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010b524742436f6e74726163741152696361726469616e436f6e747261637405013e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd8989010b524742436f6e747261637412446976697369626c654173736574537065630602066e616d696e6760fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec09707265636973696f6ec554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5b360cb3d1a1ce2559dd5cc11d2b3164467211559b80a239b16d081f394fa5b5300050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b900040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d656f23e8a03955547d9bd76db47bb7e5eea3792d5f8f223c790cc2b5eed658c09fb9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab40107426974636f696e04547869640501b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54b9ef64121db10df182d4df713abb2b2e97a73f8f9c116f81f54577c3e0bf015b010353746403446563030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80010b524742436f6e74726163740f50726f6f664f6652657365727665730602047574786fb1e43bec82e3821b2d7ccee89a7d213da8b77eea0518bcfa4f6d6f8dfe0296de0570726f6f668a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caaeba7da437dd2009266764a53302be280bec57a35edea906c42185c96e1a1d4e8400040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65470ad9ae9cbc8fa7428330b0c0a4fb32d1f9fc30a94eaa4b3c41145b849a56e9bbd8604f99b5c9047de07d559069a286d27c94143106e2f5eae266ae44f7168701035374640c416c706861436170734e756d0324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5abd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff70107426974636f696e075769746e6573730501f5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c548bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff70107426974636f696e055365714e6f0501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c1f252f38965138fc5cb730e49eda0f7f792ed6b88b2e17739d6410d251b1514010552474232310a4974656d73436f756e740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5010b524742436f6e747261637409507265636973696f6e03130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f12c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b1000000cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e430010b524742436f6e74726163740954696d657374616d70050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c752606617cb958efe9c6d304f13222e2a4907124e86e7ea1c5a74e24c3e2235f6c4d2a9a501035374640b486578446563536d616c6c0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00107426974636f696e045361747305016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b11cd2a948954a0dc1dd1a4e04145245638af3f544c133c68bf1af183cb3346668a000001d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100100000000000000ff00000000000000d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d7664010552474232310a546f6b656e496e6465780501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531d669d8d150ff6a2e7486568b066e2fb43e4efe6aab93d103d8f559d14a6ccd1500040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d658aa05647e0f89c231194d76e4f776ef7d3255028c484cb63a8a68f7d0251695ee27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000004e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba00088df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40000000000000000fffffffffffffffff27e112e62134308df24f66cd6a133e473d72977d65f49467f1fd8a4d92a13c7010353746404426f6f6c03020566616c736500047472756501f41f2a6324dcada5162bb3034f7c2a19ad40b9124fb467e44c5a0d772c430d8e010353746405416c7068610334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7af5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c5480008a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe0000000000000000fffffffffffffffff82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c0107426974636f696e0b53637269707442797465730501a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fefd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d0107426974636f696e04566f75740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000000000191da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b00dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d491da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b0403000763726561746564340804737065633508057465726d73360806746f6b656e730134080b62656e656669636961727900013408085472616e73666572000291da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b00055247423231060f6174746163686d656e74547970657301869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f60001076372656174656401cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001000a656e67726176696e677301497c7eb9391a079a38d92afdde2e4eec03a9a37987201d5ab5b14d45c17b250d0001047370656301b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100057465726d7301b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010006746f6b656e730106df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c0001030a61737365744f776e6572055d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa81000000112696e666c6174696f6e416c6c6f77616e636505c1f252f38965138fc5cb730e49eda0f7f792ed6b88b2e17739d6410d251b15140100010b75706461746552696768740101000000010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7050f6174746163686d656e745479706573000000ffff0763726561746564000100010004737065630001000100057465726d73000100010006746f6b656e73000000ffff030a61737365744f776e6572000000ffff12696e666c6174696f6e416c6c6f77616e6365000000ffff0b757064617465526967687400000001000004010304090407456e67726176650100010a656e67726176696e67730001000100010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000401020708010b62656e656669636961727905497373756501010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b702126e65774174746163686d656e745479706573010f6174746163686d656e7454797065730000ffff096e6577546f6b656e730106746f6b656e730000ffff0104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff00050103040609010b62656e65666963696172790652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff0003010207010b62656e6566696369617279009048212cad2ed6e09a3e853c904f71889286e17ec23d0a3b6326ecee721b7b9901085472616e73666572dd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce900055247423230060c6275726e6564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a0001076372656174656401cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001000c697373756564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a00010e7265706c61636564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a0001047370656301b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100057465726d7301b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae37798610700100050a61737365744f776e657202000001096275726e45706f636801010000096275726e52696768740101000112696e666c6174696f6e416c6c6f77616e6365020100010b75706461746552696768740101000000010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b704076372656174656400010001000c697373756564537570706c79000100010004737065630001000100057465726d730001000100040a61737365744f776e6572000000ffff096275726e45706f6368000000010012696e666c6174696f6e416c6c6f77616e6365000000ffff0b75706461746552696768740000000100000301030406044275726e0101f4bdcb47aa7db1caab5656f482e6788f22cf4534f93d506cdb350e13b9d0d9eb010c6275726e6564537570706c79000100010001047573656401096275726e526967687401000100010666757475726501096275726e52696768740000010000030103050005497373756501010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7010c697373756564537570706c7900010001000104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff000401030406010b62656e6566696369617279094f70656e45706f636801000001047573656401096275726e45706f63680100010002096275726e52696768740001000100046e65787401096275726e45706f636800000100000001096275726e52696768740652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265075265706c6163650101f4bdcb47aa7db1caab5656f482e6788f22cf4534f93d506cdb350e13b9d0d9eb010e7265706c61636564537570706c79000100010001047573656401096275726e526967687401000100020b62656e6566696369617279010a61737365744f776e65720000ffff0666757475726501096275726e526967687400000100000401020305010b62656e6566696369617279085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000102010b62656e65666963696172790031e4e2b06ffac24c5455a677c387081de1697ebb91ba71ef38825fc9301bc80301085472616e73666572021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f0000d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd8000000303000100040000000000d00701000c00044449424104444942410002d1070100060004004449424101d00701010003010030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f0000000022b15850d50f7ac1080500000000000000a1be14ae6fd7e13c777322802c58fd7d808f51184cfb2843bf594ffb97e790c600c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc0000dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d48000000403000100040000000000340801000c0004444942410444494241000235080100060004004449424136080100400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e6700000001340802010003013755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec74701000000393f83f1cb83ff340c0001000000010000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f00c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc000000000000000000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f03030001000000000000040000000000d007010000000000000c00044449424104444942410002d10701000000000000060004004449424100000000010000001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd00700000030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f00000000080500000000000000a1be14ae6fd7e13c777322802c58fd7d808f51184cfb2843bf594ffb97e790c6000000000000000000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bcdd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d400c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc040300010000000000000400000000003408010000000000000c000444494241044449424100023508010000000000000600040044494241360801000000000000400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e67000000000000000000000001000000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc340800003755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec747010000000c000100000001000000000000000000000000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f0000000100000030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f000000000100001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd0070000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc0000000100003755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec74701000000010000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc34080000000000000000"; diff --git a/tests/web_storage.rs b/tests/web_storage.rs index db36eace..a4e9ff15 100644 --- a/tests/web_storage.rs +++ b/tests/web_storage.rs @@ -21,7 +21,7 @@ async fn web_storage() { let data = b"Hello world!".to_vec(); info!("Testing web data store"); - resolve(store(sk.clone(), name.clone(), data.clone())).await; + resolve(store(sk.clone(), name.clone(), data.clone(), None)).await; info!("Testing web data retrieve"); let result: JsValue = resolve(retrieve(sk, name)).await; From 4ed66f9510be0d4e8ea8de1702f866c26f05e8b2 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Thu, 29 Jun 2023 03:39:17 -0600 Subject: [PATCH 08/15] Reverse argument order. Fix lints. --- .vscode/settings.json | 8 ++++---- src/bin/bitmaskd.rs | 4 ++-- src/carbonado.rs | 26 ++++++++++++++------------ src/rgb.rs | 2 +- src/rgb/carbonado.rs | 4 ++-- src/web.rs | 2 +- 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5cdaf81a..6c04de34 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,10 +5,10 @@ "files.autoSave": "onFocusChange", "files.insertFinalNewline": true, "files.trimTrailingWhitespace": true, - "rust-analyzer.cargo.features": "all", // Enable only for desktop - // "rust-analyzer.cargo.target": "wasm32-unknown-unknown", // Enable only for web - // "rust-analyzer.check.noDefaultFeatures": true, // Enable for web - // "rust-analyzer.runnables.extraArgs": ["--release"], // Enable for web + // "rust-analyzer.cargo.features": "all", // Enable only for desktop + "rust-analyzer.cargo.target": "wasm32-unknown-unknown", // Enable only for web + "rust-analyzer.check.noDefaultFeatures": true, // Enable for web + "rust-analyzer.runnables.extraArgs": ["--release"], // Enable for web "[toml]": { "editor.defaultFormatter": "tamasfe.even-better-toml" } diff --git a/src/bin/bitmaskd.rs b/src/bin/bitmaskd.rs index a3d31b57..5a24b73c 100644 --- a/src/bin/bitmaskd.rs +++ b/src/bin/bitmaskd.rs @@ -57,7 +57,7 @@ async fn reissue( info!("POST /reissue {request:?}"); let nostr_hex_sk = auth.token(); - let issue_res = reissue_contract(&nostr_hex_sk, request).await?; + let issue_res = reissue_contract(nostr_hex_sk, request).await?; Ok((StatusCode::OK, Json(issue_res))) } @@ -379,7 +379,7 @@ async fn co_metadata( .read(true) .write(true) .create(true) - .open(&filepath) + .open(filepath) { Ok(file) => { let present_header = match carbonado::file::Header::try_from(&file) { diff --git a/src/carbonado.rs b/src/carbonado.rs index a03e7254..c02cc97a 100644 --- a/src/carbonado.rs +++ b/src/carbonado.rs @@ -8,7 +8,6 @@ use anyhow::Result; #[cfg(not(feature = "server"))] use anyhow::{anyhow, Context}; use bitcoin_30::secp256k1::{PublicKey, SecretKey}; -use carbonado::file::Header; #[cfg(not(feature = "server"))] use percent_encoding::utf8_percent_encode; @@ -116,7 +115,7 @@ pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { } #[cfg(not(feature = "server"))] -pub async fn retrieve(sk: &str, name: &str) -> Result> { +pub async fn retrieve(sk: &str, name: &str) -> Result<(Vec, Option>)> { let sk = hex::decode(sk)?; let secret_key = SecretKey::from_slice(&sk)?; let public_key = PublicKey::from_secret_key_global(&secret_key); @@ -148,10 +147,11 @@ pub async fn retrieve(sk: &str, name: &str) -> Result> { let encoded = response.bytes().await?; if encoded.is_empty() { - Ok((None, Vec::new())) + Ok((Vec::new(), None)) } else { - let (_, decoded) = carbonado::file::decode(&sk, &encoded)?; - Ok(decoded) + let (header, decoded) = carbonado::file::decode(&sk, &encoded)?; + + Ok((decoded, header.metadata.map(|m| m.to_vec()))) } } @@ -174,15 +174,17 @@ pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { let bytes = fs::read(filepath).await?; let (header, _) = carbonado::file::decode(&sk, &bytes)?; - let mut result = FileMetadata::default(); - result.filename = header.file_name(); - result.metadata = header.metadata.unwrap_or_default(); + + let result = FileMetadata { + filename: header.file_name(), + metadata: header.metadata.unwrap_or_default(), + }; Ok(result) } #[cfg(feature = "server")] -pub async fn retrieve(sk: &str, name: &str) -> Result> { +pub async fn retrieve(sk: &str, name: &str) -> Result<(Vec, Option>)> { use crate::constants::NETWORK; let sk = hex::decode(sk)?; @@ -200,11 +202,11 @@ pub async fn retrieve(sk: &str, name: &str) -> Result> { let bytes = fs::read(filepath).await?; if bytes.is_empty() { - Ok((None, Vec::new())) + Ok((Vec::new(), None)) } else { - let (_, decoded) = carbonado::file::decode(&sk, &bytes)?; + let (header, decoded) = carbonado::file::decode(&sk, &bytes)?; - Ok(decoded) + Ok((decoded, header.metadata.map(|m| m.to_vec()))) } } diff --git a/src/rgb.rs b/src/rgb.rs index 9b154e33..0d076e13 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -172,7 +172,7 @@ pub async fn reissue_contract(sk: &str, request: ReIssueRequest) -> Result Result { let IssueRequest { diff --git a/src/rgb/carbonado.rs b/src/rgb/carbonado.rs index f97aac51..66bc0d8f 100644 --- a/src/rgb/carbonado.rs +++ b/src/rgb/carbonado.rs @@ -14,7 +14,7 @@ pub async fn store_stock(sk: &str, name: &str, stock: &Stock) -> Result<()> { } pub async fn retrieve_stock(sk: &str, name: &str) -> Result { - let (_, data) = retrieve(sk, name).await.unwrap_or_default(); + let (data, _) = retrieve(sk, name).await.unwrap_or_default(); if data.is_empty() { Ok(Stock::default()) } else { @@ -31,7 +31,7 @@ pub async fn store_wallets(sk: &str, name: &str, rgb_wallets: &RgbAccount) -> Re } pub async fn retrieve_wallets(sk: &str, name: &str) -> Result { - let (_, data) = retrieve(sk, name).await.unwrap_or_default(); + let (data, _) = retrieve(sk, name).await.unwrap_or_default(); if data.is_empty() { Ok(RgbAccount::default()) } else { diff --git a/src/web.rs b/src/web.rs index 8455f8c4..4f508df1 100644 --- a/src/web.rs +++ b/src/web.rs @@ -700,7 +700,7 @@ pub mod carbonado { future_to_promise(async move { match crate::carbonado::retrieve(&secret_key, &name).await { - Ok((_, result)) => { + Ok((result, _)) => { let array = Uint8Array::new_with_length(result.len() as u32); array.copy_from(&result); Ok(JsValue::from(array)) From 3f399752c74b6a287217f790241753b84fa34f1e Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Thu, 29 Jun 2023 04:28:00 -0600 Subject: [PATCH 09/15] Fix mismatched types errors. --- src/rgb.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/rgb.rs b/src/rgb.rs index 62381f80..8f545556 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -119,7 +119,7 @@ pub async fn issue_contract(sk: &str, request: IssueRequest) -> Result Result Date: Thu, 29 Jun 2023 05:24:49 -0600 Subject: [PATCH 10/15] Undo vscode setting. --- .vscode/settings.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 6c04de34..5cdaf81a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,10 +5,10 @@ "files.autoSave": "onFocusChange", "files.insertFinalNewline": true, "files.trimTrailingWhitespace": true, - // "rust-analyzer.cargo.features": "all", // Enable only for desktop - "rust-analyzer.cargo.target": "wasm32-unknown-unknown", // Enable only for web - "rust-analyzer.check.noDefaultFeatures": true, // Enable for web - "rust-analyzer.runnables.extraArgs": ["--release"], // Enable for web + "rust-analyzer.cargo.features": "all", // Enable only for desktop + // "rust-analyzer.cargo.target": "wasm32-unknown-unknown", // Enable only for web + // "rust-analyzer.check.noDefaultFeatures": true, // Enable for web + // "rust-analyzer.runnables.extraArgs": ["--release"], // Enable for web "[toml]": { "editor.defaultFormatter": "tamasfe.even-better-toml" } From 0621f95596a43f86692ebe831a4cf8deb884f7f0 Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Thu, 29 Jun 2023 13:58:10 -0300 Subject: [PATCH 11/15] refactor: allow force write file --- src/bin/bitmaskd.rs | 46 +++++++++- src/carbonado.rs | 82 +++++++++++------- src/rgb.rs | 4 +- src/rgb/carbonado.rs | 30 ++++++- src/web.rs | 3 +- tests/rgb.rs | 1 + tests/rgb/sre/st130.rs | 11 ++- tests/rgb/sre/st130_web.rs | 170 +++++++++++++++++++++++++++++++++++++ tests/web_storage.rs | 2 +- 9 files changed, 307 insertions(+), 42 deletions(-) create mode 100644 tests/rgb/sre/st130_web.rs diff --git a/src/bin/bitmaskd.rs b/src/bin/bitmaskd.rs index 5a24b73c..116c40e1 100644 --- a/src/bin/bitmaskd.rs +++ b/src/bin/bitmaskd.rs @@ -342,6 +342,49 @@ async fn co_store( Ok((StatusCode::OK, TypedHeader(cc))) } +async fn co_force_store( + Path((pk, name)): Path<(String, String)>, + body: Bytes, +) -> Result { + let incoming_header = carbonado::file::Header::try_from(&body)?; + let body_len = incoming_header.encoded_len - incoming_header.padding_len; + info!("POST /carbonado/{pk}/{name}/force, {body_len} bytes"); + + let filepath = handle_file(&pk, &name, body_len.try_into()?).await?; + + match OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&filepath) + { + Ok(file) => { + let present_header = match carbonado::file::Header::try_from(&file) { + Ok(header) => header, + _ => carbonado::file::Header::try_from(&body)?, + }; + let present_len = present_header.encoded_len - present_header.padding_len; + debug!("body len: {body_len} present_len: {present_len}"); + let resp = fs::write(&filepath, &body).await; + debug!("file override status {}", resp.is_ok()); + } + Err(err) => match err.kind() { + ErrorKind::NotFound => { + debug!("no file found, writing {body_len} bytes."); + fs::write(&filepath, &body).await?; + } + _ => { + error!("error in POST /carbonado/{pk}/{name}/force: {err}"); + return Err(err.into()); + } + }, + } + + let cc = CacheControl::new().with_no_cache(); + + Ok((StatusCode::OK, TypedHeader(cc))) +} + async fn co_retrieve( Path((pk, name)): Path<(String, String)>, ) -> Result { @@ -395,7 +438,7 @@ async fn co_metadata( fs::write(&filepath, &vec![]).await?; } _ => { - error!("error in POST /carbonado/{pk}/{name}: {err}"); + error!("error in GET /carbonado/{pk}/{name}/metadata: {err}"); return Err(err.into()); } }, @@ -457,6 +500,7 @@ async fn main() -> Result<()> { .route("/key/:pk", get(key)) .route("/carbonado/status", get(status)) .route("/carbonado/:pk/:name", post(co_store)) + .route("/carbonado/:pk/:name/force", post(co_force_store)) .route("/carbonado/:pk/:name", get(co_retrieve)) .route("/carbonado/:pk/:name/metadata", get(co_metadata)) .layer(CorsLayer::permissive()); diff --git a/src/carbonado.rs b/src/carbonado.rs index c02cc97a..45f525df 100644 --- a/src/carbonado.rs +++ b/src/carbonado.rs @@ -21,7 +21,13 @@ use crate::{ }; #[cfg(not(feature = "server"))] -pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option>) -> Result<()> { +pub async fn store( + sk: &str, + name: &str, + input: &[u8], + force: bool, + metadata: Option>, +) -> Result<()> { let level = 15; let sk = hex::decode(sk)?; let secret_key = SecretKey::from_slice(&sk)?; @@ -35,7 +41,13 @@ pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option> let endpoint = CARBONADO_ENDPOINT.read().await.to_string(); let name = utf8_percent_encode(name, FORM); let network = NETWORK.read().await.to_string(); - let url = format!("{endpoint}/{pk_hex}/{network}-{name}"); + + let mut force_write = ""; + if force { + force_write = "/force"; + } + + let url = format!("{endpoint}/{pk_hex}/{network}-{name}{force_write}"); let client = reqwest::Client::new(); let response = client .post(&url) @@ -47,7 +59,6 @@ pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option> .context(format!("Error sending JSON POST request to {url}"))?; let status_code = response.status().as_u16(); - if status_code != 200 { let response_text = response.text().await.context(format!( "Error in parsing server response for POST JSON request to {url}" @@ -62,7 +73,13 @@ pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option> } #[cfg(feature = "server")] -pub async fn store(sk: &str, name: &str, input: &[u8], metadata: Option>) -> Result<()> { +pub async fn store( + sk: &str, + name: &str, + input: &[u8], + _force: bool, + metadata: Option>, +) -> Result<()> { let level = 15; let sk = hex::decode(sk)?; let secret_key = SecretKey::from_slice(&sk)?; @@ -114,6 +131,34 @@ pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { Ok(result) } +#[cfg(feature = "server")] +pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { + use crate::constants::NETWORK; + + let sk = hex::decode(sk)?; + let secret_key = SecretKey::from_slice(&sk)?; + let public_key = PublicKey::from_secret_key_global(&secret_key); + let pk = public_key.to_hex(); + + let network = NETWORK.read().await.to_string(); + let mut final_name = name.to_string(); + if !name.contains(&network) { + final_name = format!("{network}-{name}"); + } + + let filepath = handle_file(&pk, &final_name, 0).await?; + let bytes = fs::read(filepath).await?; + + let (header, _) = carbonado::file::decode(&sk, &bytes)?; + + let result = FileMetadata { + filename: header.file_name(), + metadata: header.metadata.unwrap_or_default(), + }; + + Ok(result) +} + #[cfg(not(feature = "server"))] pub async fn retrieve(sk: &str, name: &str) -> Result<(Vec, Option>)> { let sk = hex::decode(sk)?; @@ -150,39 +195,10 @@ pub async fn retrieve(sk: &str, name: &str) -> Result<(Vec, Option>) Ok((Vec::new(), None)) } else { let (header, decoded) = carbonado::file::decode(&sk, &encoded)?; - Ok((decoded, header.metadata.map(|m| m.to_vec()))) } } -#[cfg(feature = "server")] -pub async fn retrieve_metadata(sk: &str, name: &str) -> Result { - use crate::constants::NETWORK; - - let sk = hex::decode(sk)?; - let secret_key = SecretKey::from_slice(&sk)?; - let public_key = PublicKey::from_secret_key_global(&secret_key); - let pk = public_key.to_hex(); - - let network = NETWORK.read().await.to_string(); - let mut final_name = name.to_string(); - if !name.contains(&network) { - final_name = format!("{network}-{name}"); - } - - let filepath = handle_file(&pk, &final_name, 0).await?; - let bytes = fs::read(filepath).await?; - - let (header, _) = carbonado::file::decode(&sk, &bytes)?; - - let result = FileMetadata { - filename: header.file_name(), - metadata: header.metadata.unwrap_or_default(), - }; - - Ok(result) -} - #[cfg(feature = "server")] pub async fn retrieve(sk: &str, name: &str) -> Result<(Vec, Option>)> { use crate::constants::NETWORK; diff --git a/src/rgb.rs b/src/rgb.rs index 8f545556..a0da380f 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -34,7 +34,7 @@ use crate::{ BITCOIN_EXPLORER_API, NETWORK, }, rgb::{ - carbonado::{retrieve_stock, store_stock}, + carbonado::{force_store_stock, retrieve_stock, store_stock}, issue::issue_contract as create_contract, psbt::{create_psbt as create_rgb_psbt, extract_commit}, resolvers::ExplorerResolver, @@ -306,7 +306,7 @@ pub async fn reissue_contract(sk: &str, request: ReIssueRequest) -> Result Result<()> { let data = stock.to_strict_serialized::()?; - store(sk, name, &data, Some(RGB_STRICT_TYPE_VERSION.to_vec())).await + store( + sk, + name, + &data, + false, + Some(RGB_STRICT_TYPE_VERSION.to_vec()), + ) + .await +} + +pub async fn force_store_stock(sk: &str, name: &str, stock: &Stock) -> Result<()> { + let data = stock.to_strict_serialized::()?; + store( + sk, + name, + &data, + true, + Some(RGB_STRICT_TYPE_VERSION.to_vec()), + ) + .await } pub async fn retrieve_stock(sk: &str, name: &str) -> Result { @@ -27,7 +46,14 @@ pub async fn retrieve_stock(sk: &str, name: &str) -> Result { pub async fn store_wallets(sk: &str, name: &str, rgb_wallets: &RgbAccount) -> Result<()> { let data = to_allocvec(rgb_wallets)?; - store(sk, name, &data, Some(RGB_STRICT_TYPE_VERSION.to_vec())).await + store( + sk, + name, + &data, + false, + Some(RGB_STRICT_TYPE_VERSION.to_vec()), + ) + .await } pub async fn retrieve_wallets(sk: &str, name: &str) -> Result { diff --git a/src/web.rs b/src/web.rs index 4f508df1..d799ce71 100644 --- a/src/web.rs +++ b/src/web.rs @@ -678,12 +678,13 @@ pub mod carbonado { secret_key: String, name: String, data: Vec, + force: bool, metadata: Option>, ) -> Promise { set_panic_hook(); future_to_promise(async move { - match crate::carbonado::store(&secret_key, &name, &data, metadata).await { + match crate::carbonado::store(&secret_key, &name, &data, force, metadata).await { Ok(result) => Ok(JsValue::from_string( serde_json::to_string(&result).unwrap(), )), diff --git a/tests/rgb.rs b/tests/rgb.rs index 464ffcf2..0d7de15a 100644 --- a/tests/rgb.rs +++ b/tests/rgb.rs @@ -31,5 +31,6 @@ mod rgb { mod sre { mod st130; + mod st130_web; } } diff --git a/tests/rgb/sre/st130.rs b/tests/rgb/sre/st130.rs index 0a333010..a382f6f6 100644 --- a/tests/rgb/sre/st130.rs +++ b/tests/rgb/sre/st130.rs @@ -2,10 +2,11 @@ use crate::rgb::integration::utils::ISSUER_MNEMONIC; use anyhow::{anyhow, Context}; use bitmask_core::carbonado::{retrieve_metadata, store}; +use bitmask_core::rgb::constants::RGB_STRICT_TYPE_VERSION; use bitmask_core::structs::WatcherRequest; use bitmask_core::{ bitcoin::save_mnemonic, - carbonado::constants::FORM, + carbonado::{constants::FORM, retrieve}, constants::{storage_keys::ASSETS_STOCK, BITMASK_ENDPOINT, NETWORK}, rgb::{constants::RGB_OLDEST_VERSION, reissue_contract}, structs::{ContractsResponse, ReIssueRequest, SecretString}, @@ -51,7 +52,7 @@ async fn allow_re_issue_rgb_contracts() -> anyhow::Result<()> { // 1. Retrieve metadata let fake_file_name = "fake-name.c15"; - let resp = store(issuer_sk, fake_file_name, &input, None).await; + let resp = store(issuer_sk, fake_file_name, &input, false, None).await; assert!(resp.is_ok()); let resp = retrieve_metadata(issuer_sk, fake_file_name).await; @@ -72,6 +73,12 @@ async fn allow_re_issue_rgb_contracts() -> anyhow::Result<()> { // 2. ReIssue contracts let reissue_resp = reissue_contract(issuer_sk, reissue_req).await; assert!(reissue_resp.is_ok()); + + // 3. Get File Information + let (_, header) = retrieve(issuer_sk, &file_name).await?; + let header = header.unwrap(); + assert!(!header.is_empty()); + assert_eq!(RGB_STRICT_TYPE_VERSION.to_vec(), header); } Ok(()) diff --git a/tests/rgb/sre/st130_web.rs b/tests/rgb/sre/st130_web.rs new file mode 100644 index 00000000..5b59d5dd --- /dev/null +++ b/tests/rgb/sre/st130_web.rs @@ -0,0 +1,170 @@ +#![allow(dead_code)] +#![allow(unused_imports)] +#![allow(unused_variables)] +#![cfg(target_arch = "wasm32")] +use anyhow::{anyhow, Context}; +use bitmask_core::rgb::constants::RGB_STRICT_TYPE_VERSION; +use bitmask_core::structs::FileMetadata; +use bitmask_core::structs::ReIssueResponse; +use bitmask_core::structs::WatcherRequest; +use bitmask_core::{ + bitcoin::save_mnemonic, + carbonado::constants::FORM, + constants::{storage_keys::ASSETS_STOCK, BITMASK_ENDPOINT, NETWORK}, + info, + rgb::constants::RGB_OLDEST_VERSION, + structs::{ContractsResponse, ReIssueRequest, SecretString}, + web::{ + carbonado::{retrieve_metadata, store}, + json_parse, resolve, + rgb::reissue_contract, + set_panic_hook, + }, +}; +use hex::FromHex; +use nostr_sdk::key::{PublicKey, SecretKey}; +use percent_encoding::utf8_percent_encode; +use reqwest::Client; + +use wasm_bindgen::prelude::*; +use wasm_bindgen_test::*; + +wasm_bindgen_test_configure!(run_in_browser); + +// #[wasm_bindgen_test] +#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.3.0)"] +async fn allow_re_issue_rgb_contracts() -> anyhow::Result<()> { + set_panic_hook(); + let mnemonic = env!("TEST_WALLET_SEED", "TEST_WALLET_SEED variable not set"); + let bitmask_endpoint = BITMASK_ENDPOINT.read().await.to_string(); + let issuer_keys = save_mnemonic( + &SecretString(mnemonic.to_string()), + &SecretString("".to_string()), + ) + .await?; + + // 0. Create Watcher + info!("0. Create Watcher"); + let issuer_sk = &issuer_keys.private.nostr_prv; + let client = Client::new(); + let endpoint = format!("{bitmask_endpoint}/watcher"); + let watch_req = WatcherRequest { + name: "default".to_string(), + xpub: issuer_keys.public.watcher_xpub.clone(), + force: true, + }; + let resp = client + .post(&endpoint) + .json(&watch_req) + .bearer_auth(issuer_sk) + .send() + .await; + assert!(resp.is_ok()); + + // 0. Prepare Data Test + info!("0. Prepare Data Test"); + let file_name = ASSETS_STOCK.to_string(); + let input = Vec::::from_hex(STOCK_ST_120)?; + + let resp = store_in_server(issuer_sk, &file_name, &input, None).await; + assert!(resp.is_ok()); + + // 1. Retrieve metadata + info!("1. Retrieve metadata"); + let fake_file_name = "fake-name.c15"; + resolve(store( + issuer_sk.to_string(), + fake_file_name.to_string(), + input, + false, + None, + )) + .await; + + let resp: JsValue = resolve(retrieve_metadata( + issuer_sk.to_string(), + fake_file_name.to_string(), + )) + .await; + let file_header: FileMetadata = json_parse(&resp); + + // 2. Retrieve contracts + info!("2. Retrieve contracts"); + if file_header.metadata == RGB_OLDEST_VERSION { + let endpoint = format!("{bitmask_endpoint}/contracts"); + + let result = client.get(&endpoint).bearer_auth(issuer_sk).send().await?; + + let resp = result.json::().await?; + let reissue_req = ReIssueRequest { + contracts: resp.contracts, + }; + let reissue_req = serde_wasm_bindgen::to_value(&reissue_req).expect("oh no!"); + + // 3. ReIssue contracts + info!("3. ReIssue contracts"); + let resp: JsValue = resolve(reissue_contract(issuer_sk.to_string(), reissue_req)).await; + + let resp: ReIssueResponse = json_parse(&resp); + assert!(!resp.contracts.is_empty()); + + // 4. Get File Information + info!("4. Get File Information"); + let resp: JsValue = resolve(retrieve_metadata( + issuer_sk.to_string(), + file_name.to_string(), + )) + .await; + + let file_header: FileMetadata = json_parse(&resp); + assert_eq!(RGB_STRICT_TYPE_VERSION.to_vec(), file_header.metadata); + } + + Ok(()) +} + +async fn store_in_server( + sk: &str, + name: &str, + input: &[u8], + metadata: Option<[u8; 8]>, +) -> anyhow::Result<()> { + let level = 15; + let sk = hex::decode(sk)?; + let secret_key = SecretKey::from_slice(&sk)?; + let public_key = PublicKey::from_secret_key_global(&secret_key); + let pk = public_key.serialize(); + let pk_hex = hex::encode(pk); + let (body, _encode_info) = carbonado::file::encode(&sk, Some(&pk), input, level, metadata)?; + let endpoint = BITMASK_ENDPOINT.read().await.to_string(); + let name = utf8_percent_encode(name, FORM); + let network = NETWORK.read().await.to_string(); + let url = format!("{endpoint}/carbonado/{pk_hex}/{network}-{name}"); + let client = reqwest::Client::new(); + let response = client + .post(&url) + .body(body) + .header("Content-Type", "application/octet-stream") + .header("Cache-Control", "no-cache") + .send() + .await + .context(format!("Error sending JSON POST request to {url}"))?; + + let status_code = response.status().as_u16(); + + if status_code != 200 { + let response_text = response.text().await.context(format!( + "Error in parsing server response for POST JSON request to {url}" + ))?; + + println!("{}", url); + + Err(anyhow!( + "Error in storing carbonado file, status: {status_code} error: {response_text}" + )) + } else { + Ok(()) + } +} + +const STOCK_ST_120: &str = "02d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd000000030300cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e4300100d007b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100d107b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010001d007010800c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b103030001000100d00701000100d1070100010001d0070100ffff000001d007c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10001d0070100ffff01d0070100ffff0037000017acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd010b524742436f6e7472616374044e616d65050198db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d81bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0107426974636f696e0554784f757406020576616c7565cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00c7363726970745075626b65794a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba1df1d11643dd30bf0b583883dfa61289186277ace4ad075e3c67ac0b83802eaa01035374640a486578446563436170730310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e4623bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0107426974636f696e095369675363726970740501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c3027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000403719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac600040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e38fd0b174ca8528da005d978de7dd5a2a763bb67e42ca25b935edf451344229e01035374640a416c706861536d616c6c031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e00050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d104693e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100000000000000000ffff0000000000004a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba0107426974636f696e0c5363726970745075626b65790501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c52740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560107426974636f696e084f7574706f696e7406020474786964b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab404766f7574fd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d5577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b000360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377f55accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b01035374640e41736369695072696e7461626c65035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e58a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066170000445cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80600085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b0100000000000000080000000000000060fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec010b524742436f6e74726163740b41737365744e616d696e670603067469636b657292e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506046e616d6517acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd0764657461696c733719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac661cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a25510000161dac6b5168357edbd878765f0382f79d864835c01c7e3a0d0747a235404c3ba010353746408416c7068614e756d033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a66ff6ddb2093d3e48033bbd707da2588df6a93d25b7d419c0592cadb31e8a2da0107426974636f696e02547806040776657273696f6e6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e8863206696e70757473e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba076f75747075747376ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f3086c6f636b54696d656f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e886320107426974636f696e055478566572050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066176c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110000086f0cbcc3130d8fdbd168f60ebb2477f344d85659ca1fc56d84b235072b67c74501035374640e416c7068614e756d4c6f64617368033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a6f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b0107426974636f696e084c6f636b54696d650501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253175b7c2e75f4dbfc3728201bc72c62986a08f2734cb3e50f32e6aad2f21343f5a010353746409416c70686143617073031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a76ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f300081bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0000000000000000ffffffffffffffff8a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffff0000000000008df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40107426974636f696e045478496e06040a707265764f757470757452740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560973696753637269707423bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0873657175656e6365bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff7077769746e657373bd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff791281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469010b524742436f6e74726163740744657461696c730501d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f92e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506010b524742436f6e7472616374065469636b657205015cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80698db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d800085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b01000000000000002800000000000000a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffffffffffffffffa788a36d6e35c945b224869165f2844711784f55b6b484b2f21f35397170ad8401035374640255340310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fae6894c8d85e1f4b6e7a31dabf56f6a09c1f423f6ce5fd49ea56bc025cb4f22301035374640c416c7068614e756d44617368033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7ab0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a5400073027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9962000b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010b524742436f6e74726163741152696361726469616e436f6e747261637405013e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd8989010b524742436f6e747261637412446976697369626c654173736574537065630602066e616d696e6760fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec09707265636973696f6ec554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab40107426974636f696e04547869640501b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54b9ef64121db10df182d4df713abb2b2e97a73f8f9c116f81f54577c3e0bf015b010353746403446563030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80010b524742436f6e74726163740f50726f6f664f6652657365727665730602047574786fb1e43bec82e3821b2d7ccee89a7d213da8b77eea0518bcfa4f6d6f8dfe0296de0570726f6f668a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caaebbd8604f99b5c9047de07d559069a286d27c94143106e2f5eae266ae44f7168701035374640c416c706861436170734e756d0324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5abd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff70107426974636f696e075769746e6573730501f5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c548bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff70107426974636f696e055365714e6f0501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5010b524742436f6e747261637409507265636973696f6e03130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f12c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b1000000cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e430010b524742436f6e74726163740954696d657374616d70050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c752606617cb958efe9c6d304f13222e2a4907124e86e7ea1c5a74e24c3e2235f6c4d2a9a501035374640b486578446563536d616c6c0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00107426974636f696e045361747305016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b11d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100100000000000000ff00000000000000e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000004e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba00088df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40000000000000000fffffffffffffffff27e112e62134308df24f66cd6a133e473d72977d65f49467f1fd8a4d92a13c7010353746404426f6f6c03020566616c736500047472756501f41f2a6324dcada5162bb3034f7c2a19ad40b9124fb467e44c5a0d772c430d8e010353746405416c7068610334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7af5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c5480008a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe0000000000000000fffffffffffffffff82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c0107426974636f696e0b53637269707442797465730501a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fefd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d0107426974636f696e04566f75740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253100015650fb29bac1c7616f976727b1e81234887ad96e7056f5a3cc99e4a8378b31480c00035247420300d0d007000000010004d0075650fb29bac1c7616f976727b1e81234887ad96e7056f5a3cc99e4a8378b3148000001dd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce900d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bddd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce90303000763726561746564d0070473706563d107057465726d7301d0070b62656e65666963696172790001d007085472616e7366657200dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d4000000050300cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001003408b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd898901003508b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae37798610700100360806df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c01003808869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f60100013408025d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa81000c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b105030001000100340801000100350801000100360800000100380800000100013408010001000000013408c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b100013408010001000134080100010000580000017447c77d2367544618e2aaf4e680659b9df075544650b5a4bbab699ea258c800040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d651da55835280aba3b02d1b5d02fc3fc47c267e8ed85554b0e7d13beed5c132b30065602cf1069e5dcfccabc7fd98ca570ce4eb972bddfb8c63633483dd519c19d00085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b0100000000000000400000000000000006df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c0105524742323109546f6b656e44617461060805696e646578d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d7664067469636b6572d669d8d150ff6a2e7486568b066e2fb43e4efe6aab93d103d8f559d14a6ccd15046e616d65017447c77d2367544618e2aaf4e680659b9df075544650b5a4bbab699ea258c80764657461696c73181998eeb65f373753d54b4983424050c38cb464d587d6a3741a13c69abfdc1007707265766965774cc79dab63f53b172bd53af42d3c1b9e36fdc5ba19ec625dcf99cf9ee6d23178056d65646961ba7da437dd2009266764a53302be280bec57a35edea906c42185c96e1a1d4e840b6174746163686d656e74730f1b2b5d80322340d1064fcfc7b82c98002836666b576b1eb7baf1a2d2756cff0872657365727665730c90d2700887419382cbcbd28c78d7c1b112602e4438551c3ca58ae68a975cbc0718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7010552474232310949737375654d65746106010872657365727665734d09d713e21e9bbabd91ffe3ac096102dcfe3ed8994f7089158532a139a024bb09317e1367c0edbbfffb675b5329d6554a0ec62580c5e5a5215af318270a88b3010552474232310d4f776e65644672616374696f6e05016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110c90d2700887419382cbcbd28c78d7c1b112602e4438551c3ca58ae68a975cbc00040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65affcae68cd21c376584c7b4a68de738dfad6386a7d6d3a7bbb348227976d14f80f1b2b5d80322340d1064fcfc7b82c98002836666b576b1eb7baf1a2d2756cff000a0001a84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e20000000000000000140000000000000017acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd010b524742436f6e7472616374044e616d65050198db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d8181998eeb65f373753d54b4983424050c38cb464d587d6a3741a13c69abfdc1000040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65b360cb3d1a1ce2559dd5cc11d2b3164467211559b80a239b16d081f394fa5b531bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0107426974636f696e0554784f757406020576616c7565cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00c7363726970745075626b65794a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba1da55835280aba3b02d1b5d02fc3fc47c267e8ed85554b0e7d13beed5c132b3000050117acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd1df1d11643dd30bf0b583883dfa61289186277ace4ad075e3c67ac0b83802eaa01035374640a486578446563436170730310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e4623bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0107426974636f696e095369675363726970740501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c3027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000403719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac600040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e38fd0b174ca8528da005d978de7dd5a2a763bb67e42ca25b935edf451344229e01035374640a416c706861536d616c6c031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e00050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d104693e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100000000000000000ffff000000000000470ad9ae9cbc8fa7428330b0c0a4fb32d1f9fc30a94eaa4b3c41145b849a56e9000501a84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e2497c7eb9391a079a38d92afdde2e4eec03a9a37987201d5ab5b14d45c17b250d010552474232310d456e67726176696e67446174610602096170706c696564546fd3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d766407636f6e74656e747b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da24a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba0107426974636f696e0c5363726970745075626b65790501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c4cc79dab63f53b172bd53af42d3c1b9e36fdc5ba19ec625dcf99cf9ee6d2317800040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d656022af4d5e00c75978b1d60421997e0b227b395dce5e52da8e030b6ae9174a444d09d713e21e9bbabd91ffe3ac096102dcfe3ed8994f7089158532a139a024bb0009ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc800000000000000000ffff0000000000004f46dce8279430081e45f623d0d618ed7f52efb553bc241b0d2ae7ec601c1a5c01055247423231094d6564696154797065060304747970655538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa0773756274797065b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b90763686172736574b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b952740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560107426974636f696e084f7574706f696e7406020474786964b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab404766f7574fd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d5538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa010552474232310c4d656469615265674e616d650501065602cf1069e5dcfccabc7fd98ca570ce4eb972bddfb8c63633483dd519c19d5577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b000360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377f55accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b01035374640e41736369695072696e7461626c65035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e58a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066170000445cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80600085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b010000000000000008000000000000005d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa810010552474232310a416c6c6f636174696f6e0502d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d766409317e1367c0edbbfffb675b5329d6554a0ec62580c5e5a5215af318270a88b36022af4d5e00c75978b1d60421997e0b227b395dce5e52da8e030b6ae9174a440005017b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da260fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec010b524742436f6e74726163740b41737365744e616d696e670603067469636b657292e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506046e616d6517acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd0764657461696c733719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac661cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a25510000161dac6b5168357edbd878765f0382f79d864835c01c7e3a0d0747a235404c3ba010353746408416c7068614e756d033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a66ff6ddb2093d3e48033bbd707da2588df6a93d25b7d419c0592cadb31e8a2da0107426974636f696e02547806040776657273696f6e6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e8863206696e70757473e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba076f75747075747376ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f3086c6f636b54696d656f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b695eb06afff78803151c5c7c1620648f52dca30526ce3ec3fea1ad7fcab75a8a000855accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b010000000000000014000000000000006963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e886320107426974636f696e055478566572050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066176c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110000086f0cbcc3130d8fdbd168f60ebb2477f344d85659ca1fc56d84b235072b67c74501035374640e416c7068614e756d4c6f64617368033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a6f23e8a03955547d9bd76db47bb7e5eea3792d5f8f223c790cc2b5eed658c09f0005015538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa6f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b0107426974636f696e084c6f636b54696d650501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253175b7c2e75f4dbfc3728201bc72c62986a08f2734cb3e50f32e6aad2f21343f5a010353746409416c70686143617073031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a76ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f300081bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0000000000000000ffffffffffffffff7b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da2010552474232310d456d6265646465644d65646961060204747970654f46dce8279430081e45f623d0d618ed7f52efb553bc241b0d2ae7ec601c1a5c04646174618a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f6010552474232310e4174746163686d656e74547970650602026964cd2a948954a0dc1dd1a4e04145245638af3f544c133c68bf1af183cb3346668a046e616d659819b0f8b92eac0f19205791b5016c23f78f78560bb47d74e266a9c24b0cf33e8a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffff0000000000008aa05647e0f89c231194d76e4f776ef7d3255028c484cb63a8a68f7d0251695e00050192e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be8429835068df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40107426974636f696e045478496e06040a707265764f757470757452740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560973696753637269707423bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0873657175656e6365bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff7077769746e657373bd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff79048212cad2ed6e09a3e853c904f71889286e17ec23d0a3b6326ecee721b7b9901055247423231054572726f720308106672616374696f6e4f766572666c6f77010e6e6f6e457175616c56616c756573020c696e76616c696450726f6f660314696e73756666696369656e7452657365727665730415697373756545786365656473416c6c6f77616e636506126e6f6e4672616374696f6e616c546f6b656e07126e6f6e456e6772617661626c65546f6b656e0815696e76616c69644174746163686d656e74547970650991281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469010b524742436f6e74726163740744657461696c730501d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f92e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506010b524742436f6e7472616374065469636b657205015cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb8069819b0f8b92eac0f19205791b5016c23f78f78560bb47d74e266a9c24b0cf33e010552474232310e4174746163686d656e744e616d650501695eb06afff78803151c5c7c1620648f52dca30526ce3ec3fea1ad7fcab75a8a98db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d800085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b01000000000000002800000000000000a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffffffffffffffffa788a36d6e35c945b224869165f2844711784f55b6b484b2f21f35397170ad8401035374640255340310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e2010552474232310a4174746163686d656e7406020474797065869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f606646967657374b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54ae6894c8d85e1f4b6e7a31dabf56f6a09c1f423f6ce5fd49ea56bc025cb4f22301035374640c416c7068614e756d44617368033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7aaffcae68cd21c376584c7b4a68de738dfad6386a7d6d3a7bbb348227976d14f8000501ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a5400073027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9962000b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010b524742436f6e74726163741152696361726469616e436f6e747261637405013e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd8989010b524742436f6e747261637412446976697369626c654173736574537065630602066e616d696e6760fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec09707265636973696f6ec554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5b360cb3d1a1ce2559dd5cc11d2b3164467211559b80a239b16d081f394fa5b5300050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b900040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d656f23e8a03955547d9bd76db47bb7e5eea3792d5f8f223c790cc2b5eed658c09fb9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab40107426974636f696e04547869640501b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54b9ef64121db10df182d4df713abb2b2e97a73f8f9c116f81f54577c3e0bf015b010353746403446563030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80010b524742436f6e74726163740f50726f6f664f6652657365727665730602047574786fb1e43bec82e3821b2d7ccee89a7d213da8b77eea0518bcfa4f6d6f8dfe0296de0570726f6f668a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caaeba7da437dd2009266764a53302be280bec57a35edea906c42185c96e1a1d4e8400040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65470ad9ae9cbc8fa7428330b0c0a4fb32d1f9fc30a94eaa4b3c41145b849a56e9bbd8604f99b5c9047de07d559069a286d27c94143106e2f5eae266ae44f7168701035374640c416c706861436170734e756d0324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5abd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff70107426974636f696e075769746e6573730501f5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c548bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff70107426974636f696e055365714e6f0501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c1f252f38965138fc5cb730e49eda0f7f792ed6b88b2e17739d6410d251b1514010552474232310a4974656d73436f756e740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5010b524742436f6e747261637409507265636973696f6e03130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f12c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b1000000cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e430010b524742436f6e74726163740954696d657374616d70050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c752606617cb958efe9c6d304f13222e2a4907124e86e7ea1c5a74e24c3e2235f6c4d2a9a501035374640b486578446563536d616c6c0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00107426974636f696e045361747305016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b11cd2a948954a0dc1dd1a4e04145245638af3f544c133c68bf1af183cb3346668a000001d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100100000000000000ff00000000000000d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d7664010552474232310a546f6b656e496e6465780501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531d669d8d150ff6a2e7486568b066e2fb43e4efe6aab93d103d8f559d14a6ccd1500040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d658aa05647e0f89c231194d76e4f776ef7d3255028c484cb63a8a68f7d0251695ee27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000004e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba00088df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40000000000000000fffffffffffffffff27e112e62134308df24f66cd6a133e473d72977d65f49467f1fd8a4d92a13c7010353746404426f6f6c03020566616c736500047472756501f41f2a6324dcada5162bb3034f7c2a19ad40b9124fb467e44c5a0d772c430d8e010353746405416c7068610334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7af5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c5480008a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe0000000000000000fffffffffffffffff82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c0107426974636f696e0b53637269707442797465730501a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fefd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d0107426974636f696e04566f75740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000000000191da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b00dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d491da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b0403000763726561746564340804737065633508057465726d73360806746f6b656e730134080b62656e656669636961727900013408085472616e73666572000291da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b00055247423231060f6174746163686d656e74547970657301869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f60001076372656174656401cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001000a656e67726176696e677301497c7eb9391a079a38d92afdde2e4eec03a9a37987201d5ab5b14d45c17b250d0001047370656301b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100057465726d7301b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010006746f6b656e730106df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c0001030a61737365744f776e6572055d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa81000000112696e666c6174696f6e416c6c6f77616e636505c1f252f38965138fc5cb730e49eda0f7f792ed6b88b2e17739d6410d251b15140100010b75706461746552696768740101000000010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7050f6174746163686d656e745479706573000000ffff0763726561746564000100010004737065630001000100057465726d73000100010006746f6b656e73000000ffff030a61737365744f776e6572000000ffff12696e666c6174696f6e416c6c6f77616e6365000000ffff0b757064617465526967687400000001000004010304090407456e67726176650100010a656e67726176696e67730001000100010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000401020708010b62656e656669636961727905497373756501010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b702126e65774174746163686d656e745479706573010f6174746163686d656e7454797065730000ffff096e6577546f6b656e730106746f6b656e730000ffff0104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff00050103040609010b62656e65666963696172790652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff0003010207010b62656e6566696369617279009048212cad2ed6e09a3e853c904f71889286e17ec23d0a3b6326ecee721b7b9901085472616e73666572dd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce900055247423230060c6275726e6564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a0001076372656174656401cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001000c697373756564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a00010e7265706c61636564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a0001047370656301b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100057465726d7301b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae37798610700100050a61737365744f776e657202000001096275726e45706f636801010000096275726e52696768740101000112696e666c6174696f6e416c6c6f77616e6365020100010b75706461746552696768740101000000010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b704076372656174656400010001000c697373756564537570706c79000100010004737065630001000100057465726d730001000100040a61737365744f776e6572000000ffff096275726e45706f6368000000010012696e666c6174696f6e416c6c6f77616e6365000000ffff0b75706461746552696768740000000100000301030406044275726e0101f4bdcb47aa7db1caab5656f482e6788f22cf4534f93d506cdb350e13b9d0d9eb010c6275726e6564537570706c79000100010001047573656401096275726e526967687401000100010666757475726501096275726e52696768740000010000030103050005497373756501010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7010c697373756564537570706c7900010001000104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff000401030406010b62656e6566696369617279094f70656e45706f636801000001047573656401096275726e45706f63680100010002096275726e52696768740001000100046e65787401096275726e45706f636800000100000001096275726e52696768740652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265075265706c6163650101f4bdcb47aa7db1caab5656f482e6788f22cf4534f93d506cdb350e13b9d0d9eb010e7265706c61636564537570706c79000100010001047573656401096275726e526967687401000100020b62656e6566696369617279010a61737365744f776e65720000ffff0666757475726501096275726e526967687400000100000401020305010b62656e6566696369617279085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000102010b62656e65666963696172790031e4e2b06ffac24c5455a677c387081de1697ebb91ba71ef38825fc9301bc80301085472616e73666572021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f0000d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd8000000303000100040000000000d00701000c00044449424104444942410002d1070100060004004449424101d00701010003010030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f0000000022b15850d50f7ac1080500000000000000a1be14ae6fd7e13c777322802c58fd7d808f51184cfb2843bf594ffb97e790c600c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc0000dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d48000000403000100040000000000340801000c0004444942410444494241000235080100060004004449424136080100400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e6700000001340802010003013755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec74701000000393f83f1cb83ff340c0001000000010000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f00c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc000000000000000000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f03030001000000000000040000000000d007010000000000000c00044449424104444942410002d10701000000000000060004004449424100000000010000001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd00700000030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f00000000080500000000000000a1be14ae6fd7e13c777322802c58fd7d808f51184cfb2843bf594ffb97e790c6000000000000000000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bcdd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d400c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc040300010000000000000400000000003408010000000000000c000444494241044449424100023508010000000000000600040044494241360801000000000000400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e67000000000000000000000001000000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc340800003755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec747010000000c000100000001000000000000000000000000000000000000021883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0f0000000100000030f3062f257f90b7f75dcc43703913fb4a9d202422f002ea174dc99a8da56f000000000100001883bcde391d0f323cb3678db35e3bd146f788b5cffe1d1f6fe4426a6b5adb0fd0070000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc0000000100003755b15f5c1bc22cd59267f0cfc6325a320aacd9b167f51806ec7365383ec74701000000010000c36afd9d66118328e6fdd9818d8b43489526ac3259554856a7d5494492eca9bc34080000000000000000"; diff --git a/tests/web_storage.rs b/tests/web_storage.rs index a4e9ff15..a8f8f69d 100644 --- a/tests/web_storage.rs +++ b/tests/web_storage.rs @@ -21,7 +21,7 @@ async fn web_storage() { let data = b"Hello world!".to_vec(); info!("Testing web data store"); - resolve(store(sk.clone(), name.clone(), data.clone(), None)).await; + resolve(store(sk.clone(), name.clone(), data.clone(), false, None)).await; info!("Testing web data retrieve"); let result: JsValue = resolve(retrieve(sk, name)).await; From 5f1397f47c7e7ff24c2f6aaf5730f64ef2e7f785 Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Wed, 5 Jul 2023 16:53:38 -0300 Subject: [PATCH 12/15] refactor: bump to strict-types 1.4.x --- Cargo.lock | 420 ++++++++++--------- Cargo.toml | 15 +- src/rgb/issue.rs | 22 +- src/rgb/structs.rs | 10 +- src/rgb/wallet.rs | 7 +- src/structs.rs | 1 + tests/rgb.rs | 4 +- tests/rgb/integration/import.rs | 2 +- tests/rgb/sre/{st130.rs => st140.rs} | 2 +- tests/rgb/sre/{st130_web.rs => st140_web.rs} | 2 +- 10 files changed, 251 insertions(+), 234 deletions(-) rename tests/rgb/sre/{st130.rs => st140.rs} (99%) rename tests/rgb/sre/{st130_web.rs => st140_web.rs} (99%) diff --git a/Cargo.lock b/Cargo.lock index dc7e1b27..89d6a839 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -42,7 +51,7 @@ checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ "cfg-if", "cipher 0.4.4", - "cpufeatures 0.2.8", + "cpufeatures 0.2.9", ] [[package]] @@ -76,7 +85,7 @@ checksum = "6385af946e0be015f5e1ca29c5e69c1ed455e6d955e0ba05db8537e666c144ea" dependencies = [ "amplify", "baid58", - "half 2.3.0", + "half 2.3.1", "paste", "ripemd", "serde", @@ -213,13 +222,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -307,7 +316,22 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", +] + +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", ] [[package]] @@ -546,9 +570,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" [[package]] name = "bitmask-core" @@ -617,12 +641,12 @@ dependencies = [ [[package]] name = "bitmask-enum" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9e32d7420c85055e8107e5b2463c4eeefeaac18b52359fe9f9c08a18f342b2" +checksum = "31e8b64f467fef8ee1c818404ec24691089e2043ee0b7828068aef8972625dcd" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.23", ] [[package]] @@ -936,9 +960,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -1043,7 +1067,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -1054,7 +1078,7 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" dependencies = [ "darling_core", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -1182,7 +1206,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1333,7 +1357,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -1399,6 +1423,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "gloo-console" version = "0.2.3" @@ -1460,9 +1490,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -1485,9 +1515,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "half" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9906a89f1724975a455316ae0554ceaa45ad83bb336f1125a87bfbdb9197cfa0" +checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" dependencies = [ "cfg-if", "crunchy", @@ -1561,18 +1591,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -1673,9 +1694,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -1697,10 +1718,11 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ + "futures-util", "http", "hyper", "rustls", @@ -1818,34 +1840,33 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys 0.48.0", + "hermit-abi", + "rustix 0.38.3", + "windows-sys", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "js-sys" @@ -1945,6 +1966,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" + [[package]] name = "lock_api" version = "0.4.10" @@ -2012,7 +2039,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -2120,14 +2147,23 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -2163,7 +2199,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -2220,9 +2256,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" [[package]] name = "payjoin" @@ -2261,29 +2297,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -2303,7 +2339,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ - "cpufeatures 0.2.8", + "cpufeatures 0.2.9", "opaque-debug", "universal-hash 0.4.0", ] @@ -2315,7 +2351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" dependencies = [ "cfg-if", - "cpufeatures 0.2.8", + "cpufeatures 0.2.9", "opaque-debug", "universal-hash 0.5.1", ] @@ -2391,9 +2427,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -2445,9 +2481,21 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89089e897c013b3deb627116ae56a6955a72b8bed395c9526af31c9fe528b484" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56" dependencies = [ "aho-corasick", "memchr", @@ -2456,9 +2504,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" [[package]] name = "reqwest" @@ -2506,7 +2554,7 @@ dependencies = [ [[package]] name = "rgb-contracts" version = "0.10.0-beta.2" -source = "git+https://github.com/crisdut/rgb?branch=release/bmc-v0.6#e5090e428a0bc9369877fa0fe39e8dcee857f3c7" +source = "git+https://github.com/crisdut/rgb?branch=release/bmc-v0.6#d71cb4f2a2265a1a83f94bf90e8f48046ef09b01" dependencies = [ "amplify", "baid58", @@ -2526,8 +2574,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ff930c654b3fb0d547e64188c0197c45749c1d3b86af4ab768f4576f238c12d" +source = "git+https://github.com/crisdut/rgb-core#54e7cbb905cab23440a00111f1321dc0acf2f03e" dependencies = [ "aluvm", "amplify", @@ -2547,7 +2594,7 @@ dependencies = [ [[package]] name = "rgb-persist-fs" version = "0.10.0" -source = "git+https://github.com/crisdut/rgb?branch=release/bmc-v0.6#e5090e428a0bc9369877fa0fe39e8dcee857f3c7" +source = "git+https://github.com/crisdut/rgb?branch=release/bmc-v0.6#d71cb4f2a2265a1a83f94bf90e8f48046ef09b01" dependencies = [ "amplify", "rgb-std", @@ -2557,7 +2604,7 @@ dependencies = [ [[package]] name = "rgb-schemata" version = "0.10.0-beta.1" -source = "git+https://github.com/crisdut/rgbsc?branch=release/bmc-v0.6#3ba61ba7827e8018f05b9c0dfd126e75eb7deb7f" +source = "git+https://github.com/crisdut/rgbsc?branch=release/bmc-v0.6#1724ed8dd9c1ceb5e2a422c442f3b90456e23bf8" dependencies = [ "aluvm", "amplify", @@ -2565,6 +2612,7 @@ dependencies = [ "rgb-std", "serde", "serde_json", + "sha2 0.10.7", "strict_encoding", "strict_types", ] @@ -2572,7 +2620,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.10.2" -source = "git+https://github.com/crisdut/rgb-wallet?branch=release/bmc-v0.6#3c4b0e719a5c90b4f8cbb67f59cd586060c597ae" +source = "git+https://github.com/crisdut/rgb-wallet?branch=release/bmc-v0.6#e6c5a951751762bb73502919678496df4791e916" dependencies = [ "amplify", "baid58", @@ -2590,7 +2638,7 @@ dependencies = [ [[package]] name = "rgb-wallet" version = "0.10.2" -source = "git+https://github.com/crisdut/rgb-wallet?branch=release/bmc-v0.6#3c4b0e719a5c90b4f8cbb67f59cd586060c597ae" +source = "git+https://github.com/crisdut/rgb-wallet?branch=release/bmc-v0.6#e6c5a951751762bb73502919678496df4791e916" dependencies = [ "amplify", "baid58", @@ -2632,6 +2680,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc_version" version = "0.4.0" @@ -2643,35 +2697,48 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.20" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", - "windows-sys 0.48.0", + "linux-raw-sys 0.3.8", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "0.38.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" +dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys 0.4.3", + "windows-sys", ] [[package]] name = "rustls" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" +checksum = "b19faa85ecb5197342b54f987b142fb3e30d0c90da40f80ef4fa9a726e6676ed" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.0", "sct", ] [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ "base64 0.21.2", ] @@ -2686,17 +2753,27 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustls-webpki" +version = "0.101.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89efed4bd0af2a8de0feb22ba38030244c93db56112b8aa67d27022286852b1c" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" [[package]] name = "salsa20" @@ -2710,11 +2787,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -2841,9 +2918,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "d01b7404f9d441d3ad40e6a636a7782c377d2abdbe4fa2440e2edcc2f4f10db8" dependencies = [ "serde_derive", ] @@ -2901,20 +2978,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "5dd83d6dde2b6b2d466e14d9d1acce8816dedee94f735eac6395808b3483c6d6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" dependencies = [ "itoa", "ryu", @@ -2923,10 +3000,11 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0" +checksum = "8acc4422959dd87a76cb117c191dcbffc20467f06c9100b76721dab370f24d3a" dependencies = [ + "itoa", "serde", ] @@ -2986,7 +3064,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -3009,7 +3087,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", - "cpufeatures 0.2.8", + "cpufeatures 0.2.9", "digest 0.10.7", ] @@ -3021,7 +3099,7 @@ checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if", - "cpufeatures 0.2.8", + "cpufeatures 0.2.9", "digest 0.9.0", "opaque-debug", ] @@ -3033,7 +3111,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", - "cpufeatures 0.2.8", + "cpufeatures 0.2.9", "digest 0.10.7", ] @@ -3141,12 +3219,12 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "strict_encoding" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be9dd3df80dc083d4e20ac87246a67f42b3a5016375ae5a48f292e85ccfb1bd" +checksum = "ca43fabd13842577ce6d152047796794e209625ff89d3f2434d99b742eea1c98" dependencies = [ "amplify", - "half 2.3.0", + "half 2.3.1", "serde", "strict_encoding_derive", ] @@ -3166,14 +3244,14 @@ dependencies = [ [[package]] name = "strict_types" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e611df6ed5752860c760c94509b838cd225e9e9e5de301517db195cf6f1f2cd" +checksum = "b4b1669bdf556c9a00a6a9aa9bf76d3ebec83aa4aa3e178bdfd2073157564579" dependencies = [ "amplify", "baid58", "base64 0.21.2", - "half 2.3.0", + "half 2.3.1", "indexmap 1.9.3", "serde", "serde_json", @@ -3219,9 +3297,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.22" +version = "2.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" +checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" dependencies = [ "proc-macro2", "quote", @@ -3244,8 +3322,8 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix", - "windows-sys 0.48.0", + "rustix 0.37.23", + "windows-sys", ] [[package]] @@ -3259,22 +3337,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "c16a64ba9387ef3fdae4f9c1a7f07a0997fce91985c0336f1ddc1822b3b37802" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "d14928354b01c4d6a4f0e549069adef399a284e7995c7ccca94e8a07a5346c59" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -3332,11 +3410,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -3346,7 +3425,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -3357,7 +3436,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -3486,7 +3565,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8bd22a874a2d0b70452d5597b12c537331d49060824a95f49f108994f94aa4c" dependencies = [ - "bitflags 2.3.2", + "bitflags 2.3.3", "bytes", "futures-core", "futures-util", @@ -3572,9 +3651,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" [[package]] name = "unicode-normalization" @@ -3628,7 +3707,7 @@ dependencies = [ "log", "once_cell", "rustls", - "rustls-webpki", + "rustls-webpki 0.100.1", "serde", "serde_json", "socks", @@ -3710,7 +3789,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", "wasm-bindgen-shared", ] @@ -3744,7 +3823,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3814,7 +3893,7 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" dependencies = [ - "rustls-webpki", + "rustls-webpki 0.100.1", ] [[package]] @@ -3857,21 +3936,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -3883,97 +3947,55 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.48.0" @@ -4059,7 +4081,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index dd1e15c8..745dbf2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,13 +38,12 @@ bitcoin = { version = "0.29.2", features = ["base64"] } bitcoin_hashes = "0.12.0" bitcoin_scripts = "0.10.0-alpha.2" bitcoin_blockchain = "0.10.0-alpha.2" -bp-core = "0.10.4" -commit_verify = "0.10.3" +bp-core = { version = "0.10.4", features = ["stl"] } +commit_verify = { version = "0.10.3", features = ["stl"] } bp-seals = "0.10.4" indexmap = "1.9.3" carbonado = "0.3.1" console_error_panic_hook = "0.1.7" -# directories = "4.0.1" miniscript_crate = { package = "miniscript", version = "9.0.1", features = [ "compiler", ] } @@ -72,23 +71,20 @@ psbt = { version = "0.10.0-alpha.2", features = [ "construct", ] } regex = "1.7.0" -reqwest = { version = "0.11.16", features = ["json"] } +reqwest = { version = "0.11.18", features = ["json"] } rgb-contracts = { version = "0.10.0-beta.2", default-features = false, features = [ "log", ] } rgb-wallet = { version = "0.10.2" } rgb-std = { version = "0.10.2" } -# rgb_wallet_bp = { version = "0.10.2-backport", package = "rgb-wallet", path = "../rgb-wallet" } -# rgb_std_bp = { version = "0.10.2-backport", package = "rgb-std", path = "../rgb-wallet/std" } - rgb-schemata = { version = "0.10.0-beta.1" } serde = "1.0.152" serde_json = "1.0.91" postcard = { version = "1.0.4", features = ["alloc"] } serde-encrypt = "0.7.0" -strict_types = "1.3.0" -strict_encoding = "2.3.0" +strict_types = "1.4.0" +strict_encoding = "~2.4.0" tokio = { version = "1.28.2", features = ["macros", "sync"] } [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -137,3 +133,4 @@ rgb-contracts = { git = "https://github.com/crisdut/rgb", branch = "release/bmc- rgb-schemata = { git = "https://github.com/crisdut/rgbsc", branch = "release/bmc-v0.6" } rgb-wallet = { git = "https://github.com/crisdut/rgb-wallet", branch = "release/bmc-v0.6" } rgb-std = { git = "https://github.com/crisdut/rgb-wallet", branch = "release/bmc-v0.6" } +rgb-core = { git = "https://github.com/crisdut/rgb-core" } diff --git a/src/rgb/issue.rs b/src/rgb/issue.rs index dd5b74b8..317cd216 100644 --- a/src/rgb/issue.rs +++ b/src/rgb/issue.rs @@ -7,10 +7,12 @@ use rgbstd::contract::GenesisSeal; use rgbstd::interface::rgb21::{Allocation, EmbeddedMedia, OwnedFraction, TokenData, TokenIndex}; use rgbstd::resolvers::ResolveHeight; use rgbstd::stl::{ - DivisibleAssetSpec, MediaType, Name, Precision, RicardianContract, Ticker, Timestamp, + Amount, ContractData, DivisibleAssetSpec, MediaType, Name, Precision, RicardianContract, + Ticker, Timestamp, }; use rgbstd::validation::ResolveTx; use std::str::FromStr; +use std::time::{SystemTime, UNIX_EPOCH}; use rgbstd::containers::Contract; use rgbstd::interface::{rgb20, rgb21, BuilderError, ContractBuilder}; @@ -118,7 +120,8 @@ fn issue_fungible_asset( let description: &'static str = Box::leak(description.to_string().into_boxed_str()); let precision = Precision::try_from(precision).expect("invalid precision"); let spec = DivisibleAssetSpec::new(ticker, name, precision); - let terms = RicardianContract::new(description); + let terms = RicardianContract::from_str(description).expect("invalid terms"); + let contract_data = ContractData { terms, media: None }; let created = Timestamp::default(); // Issuer State let seal = ExplicitSeal::::from_str(seal).expect("invalid seal definition"); @@ -131,9 +134,11 @@ fn issue_fungible_asset( .expect("invalid spec") .add_global_state("created", created) .expect("invalid created") - .add_global_state("terms", terms) + .add_global_state("data", contract_data) .expect("invalid contract text") - .add_fungible_state("beneficiary", seal, supply) + .add_global_state("issuedSupply", Amount::from(supply)) + .expect("invalid issued supply") + .add_fungible_state("assetOwner", seal, supply) .expect("invalid asset amount") .issue_contract() .expect("contract doesn't fit schema requirements"); @@ -161,8 +166,11 @@ fn issue_uda_asset( let description: &'static str = Box::leak(description.to_string().into_boxed_str()); let precision = Precision::try_from(precision).expect("invalid precision"); let spec = DivisibleAssetSpec::new(ticker, name, precision); - let terms = RicardianContract::new(description); - let created = Timestamp::default(); + let terms = RicardianContract::from_str(description).expect("invalid terms"); + let start = SystemTime::now(); + let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("invalid"); + let created = + Timestamp::from_str(&since_the_epoch.as_secs_f32().to_string()).expect("invalid timestamp"); let fraction = OwnedFraction::from_inner(supply); let mut tokens_data = vec![]; @@ -242,7 +250,7 @@ fn issue_uda_asset( for allocation in allocations { contract = contract - .add_data_state("beneficiary", seal, allocation) + .add_data_state("assetOwner", seal, allocation) .expect("invalid asset blob"); } diff --git a/src/rgb/structs.rs b/src/rgb/structs.rs index dba2c513..264af0b5 100644 --- a/src/rgb/structs.rs +++ b/src/rgb/structs.rs @@ -2,8 +2,7 @@ use std::{collections::HashMap, str::FromStr}; use bitcoin::Address; use bitcoin_scripts::address::AddressCompat; -use bp::Outpoint; -use rgb::{interface::OutpointFilter, RgbWallet, TerminalPath}; +use rgb::{RgbWallet, TerminalPath}; use serde::{Deserialize, Serialize}; @@ -40,10 +39,3 @@ pub struct AddressTerminal { pub address: AddressCompat, pub terminal: TerminalPath, } - -pub struct EmptyFilter {} -impl OutpointFilter for EmptyFilter { - fn include_outpoint(&self, _outpoint: Outpoint) -> bool { - true - } -} diff --git a/src/rgb/wallet.rs b/src/rgb/wallet.rs index 2d7f72be..17c6fd93 100644 --- a/src/rgb/wallet.rs +++ b/src/rgb/wallet.rs @@ -19,7 +19,6 @@ use std::{ }; use strict_encoding::tn; -use crate::rgb::structs::EmptyFilter; use crate::rgb::{resolvers::ResolveSpent, structs::AddressTerminal}; use crate::structs::{AllocationDetail, AllocationValue, UDAPosition, WatcherDetail}; @@ -311,14 +310,13 @@ where }; sync_wallet(iface_index, wallet, resolver); - let empty = EmptyFilter {}; let mut details = vec![]; for contract_id in stock.contract_ids()? { let iface = stock.iface_by_name(&tn!(iface_name))?; if let Ok(contract) = stock.contract_iface(contract_id, iface.iface_id()) { let mut owners = vec![]; for owned in &contract.iface.assignments { - if let Ok(allocations) = contract.fungible(owned.name.clone(), Some(&empty)) { + if let Ok(allocations) = contract.fungible(owned.name.clone(), &None) { for allocation in allocations { let txid = bitcoin::Txid::from_str(&allocation.owner.txid.to_hex()) .expect("invalid txid"); @@ -400,7 +398,6 @@ pub fn allocations_by_contract( where T: ResolveSpent + Resolver, { - let empty = EmptyFilter {}; let iface_name = match iface_index { 20 => "RGB20", 21 => "RGB21", @@ -412,7 +409,7 @@ where if let Ok(contract) = stock.contract_iface(contract_id, iface.iface_id()) { sync_wallet(iface_index, wallet, resolver); for owned in &contract.iface.assignments { - if let Ok(allocations) = contract.fungible(owned.name.clone(), Some(&empty)) { + if let Ok(allocations) = contract.fungible(owned.name.clone(), &None) { for allocation in allocations { let txid = bitcoin::Txid::from_str(&allocation.owner.txid.to_hex()) .expect("invalid txid"); diff --git a/src/structs.rs b/src/structs.rs index 6ea968bc..0c5c7982 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -581,6 +581,7 @@ impl UDAPosition { pub fn with(uda: AllocationUDA) -> Self { UDAPosition { token_index: uda + .clone() .token_id() .to_string() .parse() diff --git a/tests/rgb.rs b/tests/rgb.rs index 0d7de15a..6eeb89a4 100644 --- a/tests/rgb.rs +++ b/tests/rgb.rs @@ -30,7 +30,7 @@ mod rgb { } mod sre { - mod st130; - mod st130_web; + mod st140; + mod st140_web; } } diff --git a/tests/rgb/integration/import.rs b/tests/rgb/integration/import.rs index 04ffb29c..18635098 100644 --- a/tests/rgb/integration/import.rs +++ b/tests/rgb/integration/import.rs @@ -45,4 +45,4 @@ async fn allow_import_uda_contract() -> anyhow::Result<()> { } const FUNGIBLE_CONTRACT: &str = "0100000000030300596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b0100d00799624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100d10718cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010001d007010800d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c03030001000100d00701000100d1070100010001d0070100ffff000001d007d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0001d0070100ffff01d0070100ffff003c000001196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e870501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed707fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a5081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffffffffffffffff0b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0602047574786fe86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c5060570726f6f66f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef083815dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465087a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed91140000000000000000ffffffffffffffff181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb1086015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410100000000000000080000000000000018cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010501560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f9391551541cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904200401deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da8915900501e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e21e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac943750501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed72a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd071cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904220002d2519390702d9a3484b79e289e7bbf2a8cad7fb5d2bc0a5f8471dba6fa3c03c031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a30a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe7680807fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a50000000000000000ffffffffffffffff332de353e616da0cb6394a23d10773fae94ff131f4fe216b2d0001bff1c7b2fb06040776657273696f6ea87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e06696e7075747315dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465076f7574707574738ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca086c6f636b54696d6535da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c339840868f9caa65acd0874d1a06eb2ee2614cdcd537f77615c836cb9a613d93033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a35da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed73c8add893836f8c04c073d1f454d9525cf96a7d7557296fa663ddbaaefa843940334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4050163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc75014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d4050184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515408fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780000000000000000ffff000000000000596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f5be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269050107fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a55ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f00085d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f2203130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f126015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a618622d17baef06602dfe775c980e0b36b6ebae8090d8075f7513bec4b93f64d03020566616c73650004747275650163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a08fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780100000000000000ff0000000000000065eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a06020576616c756597f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b0c7363726970745075626b6579cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea490436632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f0044728ea68a97de7420f62a5969b04b872604bf45d6df38959c7e26e7a72490e4ad033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a7a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed911406040a707265764f7574707574e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50609736967536372697074cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec940873657175656e636501196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e87077769746e657373ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb258057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a50501181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000028000000000000008ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca0865eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a0000000000000000ffffffffffffffff97f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b05015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f99624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10602066e616d696e67de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff58609707265636973696f6e5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f229e14cce6b185cca477ba44634bfa2c5871a97e0c32b7aec1df6a94522a9319c70310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655605012a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdda5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed70004a62e384a135184183b9da6b9796b06e88c75c6803139dd391148ea049ae3d7e10310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66a87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48fbaa0e3fcab9d55d168bb1e26837153afe89f83a27e0498554d3963f6431fd3f4033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7abc2891b1c66ac5f5e61059a32077daa82333a1435bd34608b30b03fc017d9545030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d651deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da891590c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb32544866340360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377fcae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea4904305015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc705013f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec9405015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0000da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b408c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb325448663401000000000000004000000000000000de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff5860603067469636b65728057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5046e616d655014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d40764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0501da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b4e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50606020474786964a38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655604766f757421e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac94375eedec3ebaa08fb010f2f96e17a0e039ad87fe60771a7301f8c5e88995d05676b0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e46ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb25050130a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe768f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffff000000000000f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7afb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc694206030474797065e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0773756274797065c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c0763686172736574c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298cfba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78010001bab043436d5163f8872caa19c3c863c0878364fe504a1c6dcfb0f2d2c62dcfdb0c00035247420300d0d007000000010004d007bab043436d5163f8872caa19c3c863c0878364fe504a1c6dcfb0f2d2c62dcfdb0000019abcb19a89c3e955b796ff9044c1078e81ab142c309d8524c774094a1835838f00055247423230060c6275726e6564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e840001076372656174656401596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b01000c697373756564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e8401010e7265706c61636564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84000104737065630199624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100057465726d730118cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010100050a61737365744f776e657202000001096275726e45706f636801010000096275726e52696768740101000112696e666c6174696f6e416c6c6f77616e6365020100010b7570646174655269676874010100000001467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b04076372656174656400010001000c697373756564537570706c79000100010004737065630001000100057465726d730001000100040a61737365744f776e6572000000ffff096275726e45706f6368000000010012696e666c6174696f6e416c6c6f77616e6365000000ffff0b75706461746552696768740000000100000301030406044275726e0101318ecaa072870bd95230a9515a6aaa14982bac9e3fb15ea2528eb0405227a7a1010c6275726e6564537570706c79000100010001047573656401096275726e526967687401000100010666757475726501096275726e5269676874000001000003010305000549737375650101467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b010c697373756564537570706c7900010001000104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff000401030406010b62656e6566696369617279094f70656e45706f636801000001047573656401096275726e45706f63680100010002096275726e52696768740001000100046e65787401096275726e45706f636800000100000001096275726e52696768740652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265075265706c6163650101318ecaa072870bd95230a9515a6aaa14982bac9e3fb15ea2528eb0405227a7a1010e7265706c61636564537570706c79000100010001047573656401096275726e526967687401000100020b62656e6566696369617279010a61737365744f776e65720000ffff0666757475726501096275726e526967687400000100000401020305010b62656e6566696369617279085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000102010b62656e656669636961727900a1879e8f56bdd6fd8ca323b94f39e060643aa69a39219194d60c4c8a7c7b01c801085472616e7366657200c70931fdf90384c1f4b4f34b2543e80876e35dbf0f15b567ccec8b340b811cc99abcb19a89c3e955b796ff9044c1078e81ab142c309d8524c774094a1835838f0303000763726561746564d0070473706563d107057465726d7301d0070b62656e65666963696172790001d007085472616e7366657200000000c70931fdf90384c1f4b4f34b2543e80876e35dbf0f15b567ccec8b340b811cc98000000303000100040000000000d00701000c00044449424104444942410002d1070100060004004449424101d007010100030177326df3704bdca90c1ad9b33a2e064e88d0cd631bb71ab15619481c2ca92ce7010000002c46352ea481d989080500000000000000073dbed09d95db3df59f8ad1e443bbd0d76f31d804b7eca91f08ab85b1a94ead0000000000000000000000000000"; -const UDA_CONTRACT: &str = "0100000000050300596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b0100340899624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100350818cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010036080b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb00174601003808086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c56840100013408021870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c05030001000100340801000100350801000100360800000100380800000100013408010001000000013408d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0001340801000100013408010001000056000001196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e870501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed707fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a5081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffffffffffffffff086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684060202696477f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f63046e616d65b6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf8205940b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb001746060805696e64657865015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d067469636b6572a1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e046e616d65cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a0764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e40138880770726576696577ae5d4de320882d36a046dd72848e756a08638149d751afac47a0b77d8c2733ac056d656469611b2fd8ca8d5f1671165441ae083116506c4e265a8d7cb9869a409db9701dafaa0b6174746163686d656e7473500a5e82892023b23d60a374fea4fd1f6b3bd66fec3f396fbe8aeac319dc9f8c0872657365727665736e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a3550ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0602047574786fe86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c5060570726f6f66f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed715dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465087a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed91140000000000000000ffffffffffffffff181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb1086015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f41010000000000000008000000000000001870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd59050265015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d19ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7718cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010501560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515419ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7705015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f1a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021b080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000014000000000000001b2fd8ca8d5f1671165441ae083116506c4e265a8d7cb9869a409db9701dafaa040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d652b9fd922298de5f15323ff775a1f79d0d35619fe1298ac9047ead0edf29fb66f1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904200401deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da8915900501e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e21e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac943750501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed72a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd071cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904220002b9fd922298de5f15323ff775a1f79d0d35619fe1298ac9047ead0edf29fb66f0501faa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c025122762d2519390702d9a3484b79e289e7bbf2a8cad7fb5d2bc0a5f8471dba6fa3c03c031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a30a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe7680807fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a50000000000000000ffffffffffffffff332de353e616da0cb6394a23d10773fae94ff131f4fe216b2d0001bff1c7b2fb06040776657273696f6ea87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e06696e7075747315dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465076f7574707574738ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca086c6f636b54696d6535da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c339840868f9caa65acd0874d1a06eb2ee2614cdcd537f77615c836cb9a613d93033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a35da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed73c8add893836f8c04c073d1f454d9525cf96a7d7557296fa663ddbaaefa843940334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4050163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a406e55d3696e06af0b904b93f8a6b2baf00b19b278b2df825db46015395cda8f0501a4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72f45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b060108726573657276657347b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd47b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd090ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0000000000000000ffff000000000000500a5e82892023b23d60a374fea4fd1f6b3bd66fec3f396fbe8aeac319dc9f8c0a0001faa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c02512276000000000000000014000000000000005014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d4050184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515408fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780000000000000000ffff000000000000596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f5be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269050107fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a55ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f00085d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f2203130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f125f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8f05015014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d46015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a618622d17baef06602dfe775c980e0b36b6ebae8090d8075f7513bec4b93f64d03020566616c73650004747275650163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a08fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780100000000000000ff0000000000000065015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed765eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a06020576616c756597f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b0c7363726970745075626b6579cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea490436632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f00446b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de0308106672616374696f6e4f766572666c6f77010e6e6f6e457175616c56616c756573020c696e76616c696450726f6f660314696e73756666696369656e7452657365727665730415697373756545786365656473416c6c6f77616e636506126e6f6e4672616374696f6e616c546f6b656e07126e6f6e456e6772617661626c65546f6b656e0815696e76616c69644174746163686d656e7454797065096e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a355040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d657d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa24728ea68a97de7420f62a5969b04b872604bf45d6df38959c7e26e7a72490e4ad033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a77f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f6300017a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed911406040a707265764f7574707574e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50609736967536372697074cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec940873657175656e636501196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e87077769746e657373ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb257d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa2405010ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd8057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a50501181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000028000000000000008ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca0865eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a0000000000000000ffffffffffffffff97f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b05015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f99624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10602066e616d696e67de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff58609707265636973696f6e5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f229e14cce6b185cca477ba44634bfa2c5871a97e0c32b7aec1df6a94522a9319c70310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46da38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655605012a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdda4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72f06020474797065fb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc69420464617461f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed70004a62e384a135184183b9da6b9796b06e88c75c6803139dd391148ea049ae3d7e10310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66a7ccf154860d368a2b95e87ad394d13d7e6430ac493c7bcdbb95a1c5aea1ccb00602096170706c696564546f65015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d07636f6e74656e74a4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72fa87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48fae5d4de320882d36a046dd72848e756a08638149d751afac47a0b77d8c2733ac040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65406e55d3696e06af0b904b93f8a6b2baf00b19b278b2df825db46015395cda8fb6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf82059405011a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021bbaa0e3fcab9d55d168bb1e26837153afe89f83a27e0498554d3963f6431fd3f4033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7abc2891b1c66ac5f5e61059a32077daa82333a1435bd34608b30b03fc017d9545030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d651deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da891590c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb32544866340360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377fcae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea4904305015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc705013f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec9405015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d655f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8fd83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0000da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b408c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb325448663401000000000000004000000000000000de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff5860603067469636b65728057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5046e616d655014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d40764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0501da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b4e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50606020474786964a38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655604766f757421e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac94375e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46d05018057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5eedec3ebaa08fb010f2f96e17a0e039ad87fe60771a7301f8c5e88995d05676b0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e46ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb25050130a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe768f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffff000000000000f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7afaa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c0251227606020474797065086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684066469676573742a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebddfb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc694206030474797065e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0773756274797065c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c0763686172736574c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298cfba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78010000000001e6b0c7ab8033b92ebfff89bda3e3a4403a7c37454e4d1de2d78f7af8fe83008600055247423231060f6174746163686d656e74547970657301086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c56840001076372656174656401596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b01000a656e67726176696e677301a7ccf154860d368a2b95e87ad394d13d7e6430ac493c7bcdbb95a1c5aea1ccb0000104737065630199624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100057465726d730118cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010006746f6b656e73010b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb0017460001030a61737365744f776e6572051870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900000112696e666c6174696f6e416c6c6f77616e636505140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0100010b7570646174655269676874010100000001467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b050f6174746163686d656e745479706573000000ffff0763726561746564000100010004737065630001000100057465726d73000100010006746f6b656e73000000ffff030a61737365744f776e6572000000ffff12696e666c6174696f6e416c6c6f77616e6365000000ffff0b757064617465526967687400000001000004010304090407456e67726176650100010a656e67726176696e67730001000100010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000401020708010b62656e65666963696172790549737375650101467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b02126e65774174746163686d656e745479706573010f6174746163686d656e7454797065730000ffff096e6577546f6b656e730106746f6b656e730000ffff0104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff00050103040609010b62656e65666963696172790652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff0003010207010b62656e6566696369617279006b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de01085472616e7366657200ca0c967f8bb57d6d85c8a0d0e1ac58816aa9a8d503bb279c50d8e37655f94c73e6b0c7ab8033b92ebfff89bda3e3a4403a7c37454e4d1de2d78f7af8fe8300860403000763726561746564340804737065633508057465726d73360806746f6b656e730134080b62656e656669636961727900013408085472616e7366657200000000ca0c967f8bb57d6d85c8a0d0e1ac58816aa9a8d503bb279c50d8e37655f94c738000000403000100040000000000340801000c0004444942410444494241000235080100060004004449424136080100400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e6700000001340802010003019ee7b29502b09271f6e1f7222fdb5c276d4df6c2b4cd4e33ff960e21e353ae9401000000b4d3d37e2fe0bbb40c000100000001000000000000000000000000000000000000000000"; +const UDA_CONTRACT: &str = "010000000005d00799624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100d307596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b0100350818cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b0101003608dc87e7b9d1283426f5a64081bc65a706ad0ddc0149f615f624f24b60c2820e6001003808086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684010001a00f021870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c05d00701000100d3070100010035080100010036080000010038080000010001a00f010001000000011027d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0001a00f0100010001a00f0100010000590000004e447473c237be1dc01efc33a53be49cbbf83c66ad6ff8df306eede360892f06020474797065fdf0cf0dd76b6921b77cf7f07ec5efcd9346d2acb4a4a969b45897dfe048b3bf066469676573742a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd01196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e870501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed707fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a5081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffffffffffffffff086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684060202696477f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f63046e616d65b6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf8205940b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0602047574786fe86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c5060570726f6f66f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef08381392c3db98aa94654c635071e304e3e309a512a9a92998a83b94434dc876fd9f0602096170706c696564546f65015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d07636f6e74656e74e237f264939b57f84ebdfac0975529109542aa90e190e9c9b5fccaaae6e6c08c140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed7144daec832e6c437927b255eb99b428a87d90d50a8ccd04d7211b5b7bc5f66ce0380036e756c0003736f68010373747802036574780303656f740403656e71050361636b060362656c070262730802687409026c660a0276740b0266660c0263720d02736f0e0273690f03646c65100364633111036463321203646333130364633414046e61636b150373796e1603657462170363616e1802656d19037375621a036573631b0266731c0267731d0272731e0275731f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0364656c7f15dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465087a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed91140000000000000000ffffffffffffffff181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb1086015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f41010000000000000008000000000000001870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd59050265015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d19ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7718cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010501560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515419ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7705015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f1a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021b080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000014000000000000001cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042004021e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac943750501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed725ecc4d37bf6ba34ea4da3b30be8cf6f7f00bcc45cb25c98751865d6d87cb363040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d655cb3da10db464d5b888451d7d722c124b3b8262d8657af7202918c390ab39cd52a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd071cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904220002d2519390702d9a3484b79e289e7bbf2a8cad7fb5d2bc0a5f8471dba6fa3c03c031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a30a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe7680807fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a50000000000000000ffffffffffffffff318ecaa072870bd95230a9515a6aaa14982bac9e3fb15ea2528eb0405227a7a106010a6275726e50726f6f667347b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd332de353e616da0cb6394a23d10773fae94ff131f4fe216b2d0001bff1c7b2fb06040776657273696f6ea87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e06696e7075747315dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465076f7574707574738ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca086c6f636b54696d6535da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c339840868f9caa65acd0874d1a06eb2ee2614cdcd537f77615c836cb9a613d93033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a35da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed73c8add893836f8c04c073d1f454d9525cf96a7d7557296fa663ddbaaefa843940334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a3f02796bec013112b4731200c91b753bf5a17a0c65aa480575c616b5c36f10f90602057465726d7318cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01056d656469614cc96ae28582cc3474e4b9880265580a12180c8cc610f3b4e2d52df91aacd1f13f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4050163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b060108726573657276657347b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd47b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd090ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0000000000000000ffff0000000000004cc96ae28582cc3474e4b9880265580a12180c8cc610f3b4e2d52df91aacd1f1040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d6585b78ab36be37f6ce78bc7e3f588005c669fd12efaa6bdcdd9aae1e5b91d17e35014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d4050184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515408fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780000000000000000ffff000000000000596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f5be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269050107fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a55ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f00085cb3da10db464d5b888451d7d722c124b3b8262d8657af7202918c390ab39cd50501e237f264939b57f84ebdfac0975529109542aa90e190e9c9b5fccaaae6e6c08c5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f2203130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f125f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8f05015014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d46015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a618622d17baef06602dfe775c980e0b36b6ebae8090d8075f7513bec4b93f64d03020566616c73650004747275650163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a08fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780100000000000000ff0000000000000065015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed765eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a06020576616c756597f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b0c7363726970745075626b6579cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea490436632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f00446b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de0308106672616374696f6e4f766572666c6f77010e6e6f6e457175616c56616c756573020c696e76616c696450726f6f660314696e73756666696369656e7452657365727665730415697373756545786365656473416c6c6f77616e636506126e6f6e4672616374696f6e616c546f6b656e07126e6f6e456e6772617661626c65546f6b656e0815696e76616c69644174746163686d656e7454797065096e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a355040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d657d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa247152b94070b9b5b1506ae55b0eac24e7078df38cad8ed21d221e474901db6ed60501853638fb1d1e26ae91f84a5d474a2e14756192d19a117bbf62679d6898a3274a728ea68a97de7420f62a5969b04b872604bf45d6df38959c7e26e7a72490e4ad033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a77f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f6300017a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed911406040a707265764f7574707574e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50609736967536372697074cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec940873657175656e636501196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e87077769746e657373ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb257d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa2405010ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd8057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a50501181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb182213b6851af06f7026c383dee401ca068a030ab64892799c40ffd5be58895bc08144daec832e6c437927b255eb99b428a87d90d50a8ccd04d7211b5b7bc5f66ce0100000000000000400000000000000084de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f301000000000000002800000000000000853638fb1d1e26ae91f84a5d474a2e14756192d19a117bbf62679d6898a3274a050182213b6851af06f7026c383dee401ca068a030ab64892799c40ffd5be58895bc85b78ab36be37f6ce78bc7e3f588005c669fd12efaa6bdcdd9aae1e5b91d17e30501004e447473c237be1dc01efc33a53be49cbbf83c66ad6ff8df306eede360892f888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e8405015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f88ec906b4268285b161323d5b85da01d0e5dc939bb96fdfae1f004cb74403dd5040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d657152b94070b9b5b1506ae55b0eac24e7078df38cad8ed21d221e474901db6ed68ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca0865eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a0000000000000000ffffffffffffffff91decb7869e65e232f6009122e5c9beceb2e9a1ed1ce39fea7df4408370628ab0a77f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f63004e447473c237be1dc01efc33a53be49cbbf83c66ad6ff8df306eede360892f0000000000000000140000000000000097f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b05015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f99624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10602066e616d696e67de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff58609707265636973696f6e5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f229e14cce6b185cca477ba44634bfa2c5871a97e0c32b7aec1df6a94522a9319c70310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46da38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655605012a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdda5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed70004a62e384a135184183b9da6b9796b06e88c75c6803139dd391148ea049ae3d7e10310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66a87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48fb6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf82059405011a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021bbaa0e3fcab9d55d168bb1e26837153afe89f83a27e0498554d3963f6431fd3f4033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7abc2891b1c66ac5f5e61059a32077daa82333a1435bd34608b30b03fc017d9545030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea4904305015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc705013f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec9405015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d655f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8fd83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0000dc87e7b9d1283426f5a64081bc65a706ad0ddc0149f615f624f24b60c2820e60060805696e64657865015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d067469636b6572a1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e046e616d65cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a0764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888077072657669657725ecc4d37bf6ba34ea4da3b30be8cf6f7f00bcc45cb25c98751865d6d87cb363056d656469614cc96ae28582cc3474e4b9880265580a12180c8cc610f3b4e2d52df91aacd1f10b6174746163686d656e747391decb7869e65e232f6009122e5c9beceb2e9a1ed1ce39fea7df4408370628ab0872657365727665736e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a355de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff5860603067469636b65728057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5046e616d655014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d40764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888e237f264939b57f84ebdfac0975529109542aa90e190e9c9b5fccaaae6e6c08c06020474797065fdf0cf0dd76b6921b77cf7f07ec5efcd9346d2acb4a4a969b45897dfe048b3bf0464617461f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50606020474786964a38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655604766f757421e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac94375e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46d05018057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5eedec3ebaa08fb010f2f96e17a0e039ad87fe60771a7301f8c5e88995d05676b0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e46ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb25050130a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe768f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffff000000000000f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7afba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da7801fdf0cf0dd76b6921b77cf7f07ec5efcd9346d2acb4a4a969b45897dfe048b3bf06030474797065853638fb1d1e26ae91f84a5d474a2e14756192d19a117bbf62679d6898a3274a077375627479706588ec906b4268285b161323d5b85da01d0e5dc939bb96fdfae1f004cb74403dd5076368617273657488ec906b4268285b161323d5b85da01d0e5dc939bb96fdfae1f004cb74403dd50000000001e4383a58b91eeafbec48c387fb18601ecdbfd2253ed700347486ecdeba469d2e00055247423231060f6174746163686d656e74547970657301086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c56840001076372656174656401596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b01000a656e67726176696e6773011392c3db98aa94654c635071e304e3e309a512a9a92998a83b94434dc876fd9f000104737065630199624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100057465726d730118cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010006746f6b656e7301dc87e7b9d1283426f5a64081bc65a706ad0ddc0149f615f624f24b60c2820e600001030a61737365744f776e6572051870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900000112696e666c6174696f6e416c6c6f77616e636505140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0100010b7570646174655269676874010100000001467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b050f6174746163686d656e745479706573000000ffff0763726561746564000100010004737065630001000100057465726d73000100010006746f6b656e73000000ffff030a61737365744f776e6572000000ffff12696e666c6174696f6e416c6c6f77616e6365000000ffff0b757064617465526967687400000001000004010304090407456e67726176650100010a656e67726176696e67730001000100010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000401020708010b62656e65666963696172790549737375650101467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b02126e65774174746163686d656e745479706573010f6174746163686d656e7454797065730000ffff096e6577546f6b656e730106746f6b656e730000ffff0104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff00050103040609010b62656e65666963696172790652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff0003010207010b62656e6566696369617279006b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de01085472616e7366657200cd894055e5040efd730dd590476931d6cfa823086d5c4dfc1396b37e0741ffa5e4383a58b91eeafbec48c387fb18601ecdbfd2253ed700347486ecdeba469d2e04d0070473706563d30707637265617465643508057465726d73360806746f6b656e7301a00f0a61737365744f776e657200011027085472616e7366657200000000cd894055e5040efd730dd590476931d6cfa823086d5c4dfc1396b37e0741ffa580000004d00701000c00044449424104444942410002d3070100040088cca56435080100060004004449424136080100400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e6700000001a00f020100030105b41f029f91e5fe7aaa5fdb48c840fb9fb67e3e6f448db96f87e88c3a9dd64d00000000b603038e127d7dcd0c000100000001000000000000000000000000000000000000000000"; diff --git a/tests/rgb/sre/st130.rs b/tests/rgb/sre/st140.rs similarity index 99% rename from tests/rgb/sre/st130.rs rename to tests/rgb/sre/st140.rs index a382f6f6..d763526f 100644 --- a/tests/rgb/sre/st130.rs +++ b/tests/rgb/sre/st140.rs @@ -17,7 +17,7 @@ use percent_encoding::utf8_percent_encode; use reqwest::Client; #[tokio::test] -#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.3.0)"] +#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.4.0)"] async fn allow_re_issue_rgb_contracts() -> anyhow::Result<()> { let bitmask_endpoint = BITMASK_ENDPOINT.read().await.to_string(); let issuer_keys = save_mnemonic( diff --git a/tests/rgb/sre/st130_web.rs b/tests/rgb/sre/st140_web.rs similarity index 99% rename from tests/rgb/sre/st130_web.rs rename to tests/rgb/sre/st140_web.rs index 5b59d5dd..e3059b82 100644 --- a/tests/rgb/sre/st130_web.rs +++ b/tests/rgb/sre/st140_web.rs @@ -32,7 +32,7 @@ use wasm_bindgen_test::*; wasm_bindgen_test_configure!(run_in_browser); // #[wasm_bindgen_test] -#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.3.0)"] +#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.4.0)"] async fn allow_re_issue_rgb_contracts() -> anyhow::Result<()> { set_panic_hook(); let mnemonic = env!("TEST_WALLET_SEED", "TEST_WALLET_SEED variable not set"); From 99d963f8ea616eaa9801fe9c6c2a68e16e532be7 Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Wed, 5 Jul 2023 17:42:54 -0300 Subject: [PATCH 13/15] chore: comment expensive tests --- tests/rgb.rs | 12 +++++++----- tests/rgb/integration/utils.rs | 1 + tests/rgb/web/imports.rs | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/rgb.rs b/tests/rgb.rs index 6eeb89a4..36af1c6b 100644 --- a/tests/rgb.rs +++ b/tests/rgb.rs @@ -12,13 +12,15 @@ mod rgb { // TODO: Review after support multi-token transfer // mod collectibles; mod collectibles; - mod fungibles; + mod import; mod issue; - mod states; - mod stress; - mod transfers; - mod udas; + // TODO: Uncomment after fixing slow encoding/decoding of strict type + // mod fungibles; + // mod states; + // mod stress; + // mod transfers; + // mod udas; pub mod utils; mod watcher; } diff --git a/tests/rgb/integration/utils.rs b/tests/rgb/integration/utils.rs index a1b82060..772b7a4f 100644 --- a/tests/rgb/integration/utils.rs +++ b/tests/rgb/integration/utils.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] #![cfg(not(target_arch = "wasm32"))] use std::{collections::HashMap, env, process::Stdio}; diff --git a/tests/rgb/web/imports.rs b/tests/rgb/web/imports.rs index ad4c7ef2..058bfcb1 100644 --- a/tests/rgb/web/imports.rs +++ b/tests/rgb/web/imports.rs @@ -213,4 +213,4 @@ async fn asset_transfer() { const FUNGIBLE_CONTRACT: &str = "0100000000030300596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b0100d00799624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100d10718cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010001d007010800d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c03030001000100d00701000100d1070100010001d0070100ffff000001d007d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0001d0070100ffff01d0070100ffff003c000001196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e870501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed707fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a5081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffffffffffffffff0b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0602047574786fe86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c5060570726f6f66f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef083815dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465087a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed91140000000000000000ffffffffffffffff181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb1086015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410100000000000000080000000000000018cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010501560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f9391551541cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904200401deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da8915900501e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e21e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac943750501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed72a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd071cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904220002d2519390702d9a3484b79e289e7bbf2a8cad7fb5d2bc0a5f8471dba6fa3c03c031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a30a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe7680807fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a50000000000000000ffffffffffffffff332de353e616da0cb6394a23d10773fae94ff131f4fe216b2d0001bff1c7b2fb06040776657273696f6ea87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e06696e7075747315dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465076f7574707574738ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca086c6f636b54696d6535da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c339840868f9caa65acd0874d1a06eb2ee2614cdcd537f77615c836cb9a613d93033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a35da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed73c8add893836f8c04c073d1f454d9525cf96a7d7557296fa663ddbaaefa843940334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4050163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc75014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d4050184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515408fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780000000000000000ffff000000000000596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f5be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269050107fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a55ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f00085d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f2203130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f126015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a618622d17baef06602dfe775c980e0b36b6ebae8090d8075f7513bec4b93f64d03020566616c73650004747275650163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a08fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780100000000000000ff0000000000000065eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a06020576616c756597f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b0c7363726970745075626b6579cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea490436632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f0044728ea68a97de7420f62a5969b04b872604bf45d6df38959c7e26e7a72490e4ad033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a7a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed911406040a707265764f7574707574e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50609736967536372697074cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec940873657175656e636501196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e87077769746e657373ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb258057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a50501181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000028000000000000008ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca0865eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a0000000000000000ffffffffffffffff97f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b05015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f99624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10602066e616d696e67de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff58609707265636973696f6e5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f229e14cce6b185cca477ba44634bfa2c5871a97e0c32b7aec1df6a94522a9319c70310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655605012a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdda5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed70004a62e384a135184183b9da6b9796b06e88c75c6803139dd391148ea049ae3d7e10310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66a87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48fbaa0e3fcab9d55d168bb1e26837153afe89f83a27e0498554d3963f6431fd3f4033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7abc2891b1c66ac5f5e61059a32077daa82333a1435bd34608b30b03fc017d9545030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d651deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da891590c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb32544866340360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377fcae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea4904305015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc705013f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec9405015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0000da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b408c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb325448663401000000000000004000000000000000de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff5860603067469636b65728057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5046e616d655014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d40764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0501da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b4e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50606020474786964a38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655604766f757421e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac94375eedec3ebaa08fb010f2f96e17a0e039ad87fe60771a7301f8c5e88995d05676b0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e46ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb25050130a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe768f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffff000000000000f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7afb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc694206030474797065e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0773756274797065c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c0763686172736574c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298cfba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78010001bab043436d5163f8872caa19c3c863c0878364fe504a1c6dcfb0f2d2c62dcfdb0c00035247420300d0d007000000010004d007bab043436d5163f8872caa19c3c863c0878364fe504a1c6dcfb0f2d2c62dcfdb0000019abcb19a89c3e955b796ff9044c1078e81ab142c309d8524c774094a1835838f00055247423230060c6275726e6564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e840001076372656174656401596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b01000c697373756564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e8401010e7265706c61636564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84000104737065630199624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100057465726d730118cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010100050a61737365744f776e657202000001096275726e45706f636801010000096275726e52696768740101000112696e666c6174696f6e416c6c6f77616e6365020100010b7570646174655269676874010100000001467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b04076372656174656400010001000c697373756564537570706c79000100010004737065630001000100057465726d730001000100040a61737365744f776e6572000000ffff096275726e45706f6368000000010012696e666c6174696f6e416c6c6f77616e6365000000ffff0b75706461746552696768740000000100000301030406044275726e0101318ecaa072870bd95230a9515a6aaa14982bac9e3fb15ea2528eb0405227a7a1010c6275726e6564537570706c79000100010001047573656401096275726e526967687401000100010666757475726501096275726e5269676874000001000003010305000549737375650101467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b010c697373756564537570706c7900010001000104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff000401030406010b62656e6566696369617279094f70656e45706f636801000001047573656401096275726e45706f63680100010002096275726e52696768740001000100046e65787401096275726e45706f636800000100000001096275726e52696768740652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265075265706c6163650101318ecaa072870bd95230a9515a6aaa14982bac9e3fb15ea2528eb0405227a7a1010e7265706c61636564537570706c79000100010001047573656401096275726e526967687401000100020b62656e6566696369617279010a61737365744f776e65720000ffff0666757475726501096275726e526967687400000100000401020305010b62656e6566696369617279085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000102010b62656e656669636961727900a1879e8f56bdd6fd8ca323b94f39e060643aa69a39219194d60c4c8a7c7b01c801085472616e7366657200c70931fdf90384c1f4b4f34b2543e80876e35dbf0f15b567ccec8b340b811cc99abcb19a89c3e955b796ff9044c1078e81ab142c309d8524c774094a1835838f0303000763726561746564d0070473706563d107057465726d7301d0070b62656e65666963696172790001d007085472616e7366657200000000c70931fdf90384c1f4b4f34b2543e80876e35dbf0f15b567ccec8b340b811cc98000000303000100040000000000d00701000c00044449424104444942410002d1070100060004004449424101d007010100030177326df3704bdca90c1ad9b33a2e064e88d0cd631bb71ab15619481c2ca92ce7010000002c46352ea481d989080500000000000000073dbed09d95db3df59f8ad1e443bbd0d76f31d804b7eca91f08ab85b1a94ead0000000000000000000000000000"; -const UDA_CONTRACT: &str = "0100000000050300596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b0100340899624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100350818cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010036080b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb00174601003808086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c56840100013408021870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c05030001000100340801000100350801000100360800000100380800000100013408010001000000013408d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0001340801000100013408010001000056000001196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e870501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed707fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a5081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffffffffffffffff086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684060202696477f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f63046e616d65b6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf8205940b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb001746060805696e64657865015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d067469636b6572a1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e046e616d65cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a0764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e40138880770726576696577ae5d4de320882d36a046dd72848e756a08638149d751afac47a0b77d8c2733ac056d656469611b2fd8ca8d5f1671165441ae083116506c4e265a8d7cb9869a409db9701dafaa0b6174746163686d656e7473500a5e82892023b23d60a374fea4fd1f6b3bd66fec3f396fbe8aeac319dc9f8c0872657365727665736e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a3550ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0602047574786fe86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c5060570726f6f66f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed715dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465087a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed91140000000000000000ffffffffffffffff181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb1086015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f41010000000000000008000000000000001870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd59050265015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d19ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7718cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010501560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515419ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7705015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f1a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021b080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000014000000000000001b2fd8ca8d5f1671165441ae083116506c4e265a8d7cb9869a409db9701dafaa040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d652b9fd922298de5f15323ff775a1f79d0d35619fe1298ac9047ead0edf29fb66f1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904200401deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da8915900501e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e21e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac943750501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed72a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd071cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904220002b9fd922298de5f15323ff775a1f79d0d35619fe1298ac9047ead0edf29fb66f0501faa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c025122762d2519390702d9a3484b79e289e7bbf2a8cad7fb5d2bc0a5f8471dba6fa3c03c031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a30a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe7680807fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a50000000000000000ffffffffffffffff332de353e616da0cb6394a23d10773fae94ff131f4fe216b2d0001bff1c7b2fb06040776657273696f6ea87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e06696e7075747315dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465076f7574707574738ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca086c6f636b54696d6535da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c339840868f9caa65acd0874d1a06eb2ee2614cdcd537f77615c836cb9a613d93033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a35da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed73c8add893836f8c04c073d1f454d9525cf96a7d7557296fa663ddbaaefa843940334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4050163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a406e55d3696e06af0b904b93f8a6b2baf00b19b278b2df825db46015395cda8f0501a4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72f45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b060108726573657276657347b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd47b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd090ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0000000000000000ffff000000000000500a5e82892023b23d60a374fea4fd1f6b3bd66fec3f396fbe8aeac319dc9f8c0a0001faa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c02512276000000000000000014000000000000005014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d4050184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515408fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780000000000000000ffff000000000000596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f5be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269050107fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a55ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f00085d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f2203130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f125f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8f05015014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d46015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a618622d17baef06602dfe775c980e0b36b6ebae8090d8075f7513bec4b93f64d03020566616c73650004747275650163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a08fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780100000000000000ff0000000000000065015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed765eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a06020576616c756597f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b0c7363726970745075626b6579cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea490436632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f00446b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de0308106672616374696f6e4f766572666c6f77010e6e6f6e457175616c56616c756573020c696e76616c696450726f6f660314696e73756666696369656e7452657365727665730415697373756545786365656473416c6c6f77616e636506126e6f6e4672616374696f6e616c546f6b656e07126e6f6e456e6772617661626c65546f6b656e0815696e76616c69644174746163686d656e7454797065096e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a355040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d657d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa24728ea68a97de7420f62a5969b04b872604bf45d6df38959c7e26e7a72490e4ad033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a77f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f6300017a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed911406040a707265764f7574707574e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50609736967536372697074cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec940873657175656e636501196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e87077769746e657373ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb257d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa2405010ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd8057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a50501181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000028000000000000008ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca0865eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a0000000000000000ffffffffffffffff97f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b05015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f99624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10602066e616d696e67de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff58609707265636973696f6e5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f229e14cce6b185cca477ba44634bfa2c5871a97e0c32b7aec1df6a94522a9319c70310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46da38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655605012a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdda4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72f06020474797065fb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc69420464617461f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed70004a62e384a135184183b9da6b9796b06e88c75c6803139dd391148ea049ae3d7e10310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66a7ccf154860d368a2b95e87ad394d13d7e6430ac493c7bcdbb95a1c5aea1ccb00602096170706c696564546f65015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d07636f6e74656e74a4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72fa87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48fae5d4de320882d36a046dd72848e756a08638149d751afac47a0b77d8c2733ac040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65406e55d3696e06af0b904b93f8a6b2baf00b19b278b2df825db46015395cda8fb6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf82059405011a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021bbaa0e3fcab9d55d168bb1e26837153afe89f83a27e0498554d3963f6431fd3f4033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7abc2891b1c66ac5f5e61059a32077daa82333a1435bd34608b30b03fc017d9545030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d651deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da891590c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb32544866340360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377fcae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea4904305015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc705013f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec9405015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d655f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8fd83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0000da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b408c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb325448663401000000000000004000000000000000de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff5860603067469636b65728057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5046e616d655014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d40764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0501da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b4e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50606020474786964a38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655604766f757421e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac94375e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46d05018057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5eedec3ebaa08fb010f2f96e17a0e039ad87fe60771a7301f8c5e88995d05676b0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e46ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb25050130a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe768f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffff000000000000f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7afaa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c0251227606020474797065086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684066469676573742a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebddfb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc694206030474797065e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0773756274797065c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c0763686172736574c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298cfba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78010000000001e6b0c7ab8033b92ebfff89bda3e3a4403a7c37454e4d1de2d78f7af8fe83008600055247423231060f6174746163686d656e74547970657301086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c56840001076372656174656401596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b01000a656e67726176696e677301a7ccf154860d368a2b95e87ad394d13d7e6430ac493c7bcdbb95a1c5aea1ccb0000104737065630199624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100057465726d730118cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010006746f6b656e73010b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb0017460001030a61737365744f776e6572051870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900000112696e666c6174696f6e416c6c6f77616e636505140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0100010b7570646174655269676874010100000001467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b050f6174746163686d656e745479706573000000ffff0763726561746564000100010004737065630001000100057465726d73000100010006746f6b656e73000000ffff030a61737365744f776e6572000000ffff12696e666c6174696f6e416c6c6f77616e6365000000ffff0b757064617465526967687400000001000004010304090407456e67726176650100010a656e67726176696e67730001000100010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000401020708010b62656e65666963696172790549737375650101467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b02126e65774174746163686d656e745479706573010f6174746163686d656e7454797065730000ffff096e6577546f6b656e730106746f6b656e730000ffff0104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff00050103040609010b62656e65666963696172790652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff0003010207010b62656e6566696369617279006b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de01085472616e7366657200ca0c967f8bb57d6d85c8a0d0e1ac58816aa9a8d503bb279c50d8e37655f94c73e6b0c7ab8033b92ebfff89bda3e3a4403a7c37454e4d1de2d78f7af8fe8300860403000763726561746564340804737065633508057465726d73360806746f6b656e730134080b62656e656669636961727900013408085472616e7366657200000000ca0c967f8bb57d6d85c8a0d0e1ac58816aa9a8d503bb279c50d8e37655f94c738000000403000100040000000000340801000c0004444942410444494241000235080100060004004449424136080100400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e6700000001340802010003019ee7b29502b09271f6e1f7222fdb5c276d4df6c2b4cd4e33ff960e21e353ae9401000000b4d3d37e2fe0bbb40c000100000001000000000000000000000000000000000000000000"; +const UDA_CONTRACT: &str = "010000000005d00799624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100d307596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b0100350818cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b0101003608dc87e7b9d1283426f5a64081bc65a706ad0ddc0149f615f624f24b60c2820e6001003808086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684010001a00f021870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c05d00701000100d3070100010035080100010036080000010038080000010001a00f010001000000011027d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0001a00f0100010001a00f0100010000590000004e447473c237be1dc01efc33a53be49cbbf83c66ad6ff8df306eede360892f06020474797065fdf0cf0dd76b6921b77cf7f07ec5efcd9346d2acb4a4a969b45897dfe048b3bf066469676573742a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd01196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e870501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed707fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a5081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffffffffffffffff086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684060202696477f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f63046e616d65b6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf8205940b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0602047574786fe86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c5060570726f6f66f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef08381392c3db98aa94654c635071e304e3e309a512a9a92998a83b94434dc876fd9f0602096170706c696564546f65015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d07636f6e74656e74e237f264939b57f84ebdfac0975529109542aa90e190e9c9b5fccaaae6e6c08c140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed7144daec832e6c437927b255eb99b428a87d90d50a8ccd04d7211b5b7bc5f66ce0380036e756c0003736f68010373747802036574780303656f740403656e71050361636b060362656c070262730802687409026c660a0276740b0266660c0263720d02736f0e0273690f03646c65100364633111036463321203646333130364633414046e61636b150373796e1603657462170363616e1802656d19037375621a036573631b0266731c0267731d0272731e0275731f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0364656c7f15dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465087a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed91140000000000000000ffffffffffffffff181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb1086015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f41010000000000000008000000000000001870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd59050265015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d19ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7718cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010501560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515419ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7705015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f1a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021b080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000014000000000000001cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042004021e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac943750501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed725ecc4d37bf6ba34ea4da3b30be8cf6f7f00bcc45cb25c98751865d6d87cb363040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d655cb3da10db464d5b888451d7d722c124b3b8262d8657af7202918c390ab39cd52a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd071cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904220002d2519390702d9a3484b79e289e7bbf2a8cad7fb5d2bc0a5f8471dba6fa3c03c031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a30a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe7680807fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a50000000000000000ffffffffffffffff318ecaa072870bd95230a9515a6aaa14982bac9e3fb15ea2528eb0405227a7a106010a6275726e50726f6f667347b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd332de353e616da0cb6394a23d10773fae94ff131f4fe216b2d0001bff1c7b2fb06040776657273696f6ea87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e06696e7075747315dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465076f7574707574738ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca086c6f636b54696d6535da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c339840868f9caa65acd0874d1a06eb2ee2614cdcd537f77615c836cb9a613d93033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a35da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed73c8add893836f8c04c073d1f454d9525cf96a7d7557296fa663ddbaaefa843940334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a3f02796bec013112b4731200c91b753bf5a17a0c65aa480575c616b5c36f10f90602057465726d7318cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01056d656469614cc96ae28582cc3474e4b9880265580a12180c8cc610f3b4e2d52df91aacd1f13f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4050163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b060108726573657276657347b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd47b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd090ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0000000000000000ffff0000000000004cc96ae28582cc3474e4b9880265580a12180c8cc610f3b4e2d52df91aacd1f1040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d6585b78ab36be37f6ce78bc7e3f588005c669fd12efaa6bdcdd9aae1e5b91d17e35014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d4050184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515408fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780000000000000000ffff000000000000596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f5be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269050107fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a55ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f00085cb3da10db464d5b888451d7d722c124b3b8262d8657af7202918c390ab39cd50501e237f264939b57f84ebdfac0975529109542aa90e190e9c9b5fccaaae6e6c08c5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f2203130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f125f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8f05015014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d46015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a618622d17baef06602dfe775c980e0b36b6ebae8090d8075f7513bec4b93f64d03020566616c73650004747275650163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a08fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780100000000000000ff0000000000000065015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed765eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a06020576616c756597f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b0c7363726970745075626b6579cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea490436632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f00446b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de0308106672616374696f6e4f766572666c6f77010e6e6f6e457175616c56616c756573020c696e76616c696450726f6f660314696e73756666696369656e7452657365727665730415697373756545786365656473416c6c6f77616e636506126e6f6e4672616374696f6e616c546f6b656e07126e6f6e456e6772617661626c65546f6b656e0815696e76616c69644174746163686d656e7454797065096e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a355040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d657d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa247152b94070b9b5b1506ae55b0eac24e7078df38cad8ed21d221e474901db6ed60501853638fb1d1e26ae91f84a5d474a2e14756192d19a117bbf62679d6898a3274a728ea68a97de7420f62a5969b04b872604bf45d6df38959c7e26e7a72490e4ad033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a77f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f6300017a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed911406040a707265764f7574707574e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50609736967536372697074cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec940873657175656e636501196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e87077769746e657373ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb257d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa2405010ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd8057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a50501181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb182213b6851af06f7026c383dee401ca068a030ab64892799c40ffd5be58895bc08144daec832e6c437927b255eb99b428a87d90d50a8ccd04d7211b5b7bc5f66ce0100000000000000400000000000000084de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f301000000000000002800000000000000853638fb1d1e26ae91f84a5d474a2e14756192d19a117bbf62679d6898a3274a050182213b6851af06f7026c383dee401ca068a030ab64892799c40ffd5be58895bc85b78ab36be37f6ce78bc7e3f588005c669fd12efaa6bdcdd9aae1e5b91d17e30501004e447473c237be1dc01efc33a53be49cbbf83c66ad6ff8df306eede360892f888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e8405015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f88ec906b4268285b161323d5b85da01d0e5dc939bb96fdfae1f004cb74403dd5040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d657152b94070b9b5b1506ae55b0eac24e7078df38cad8ed21d221e474901db6ed68ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca0865eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a0000000000000000ffffffffffffffff91decb7869e65e232f6009122e5c9beceb2e9a1ed1ce39fea7df4408370628ab0a77f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f63004e447473c237be1dc01efc33a53be49cbbf83c66ad6ff8df306eede360892f0000000000000000140000000000000097f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b05015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f99624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10602066e616d696e67de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff58609707265636973696f6e5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f229e14cce6b185cca477ba44634bfa2c5871a97e0c32b7aec1df6a94522a9319c70310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46da38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655605012a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdda5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed70004a62e384a135184183b9da6b9796b06e88c75c6803139dd391148ea049ae3d7e10310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66a87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48fb6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf82059405011a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021bbaa0e3fcab9d55d168bb1e26837153afe89f83a27e0498554d3963f6431fd3f4033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7abc2891b1c66ac5f5e61059a32077daa82333a1435bd34608b30b03fc017d9545030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea4904305015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc705013f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec9405015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d655f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8fd83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0000dc87e7b9d1283426f5a64081bc65a706ad0ddc0149f615f624f24b60c2820e60060805696e64657865015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d067469636b6572a1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e046e616d65cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a0764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888077072657669657725ecc4d37bf6ba34ea4da3b30be8cf6f7f00bcc45cb25c98751865d6d87cb363056d656469614cc96ae28582cc3474e4b9880265580a12180c8cc610f3b4e2d52df91aacd1f10b6174746163686d656e747391decb7869e65e232f6009122e5c9beceb2e9a1ed1ce39fea7df4408370628ab0872657365727665736e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a355de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff5860603067469636b65728057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5046e616d655014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d40764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888e237f264939b57f84ebdfac0975529109542aa90e190e9c9b5fccaaae6e6c08c06020474797065fdf0cf0dd76b6921b77cf7f07ec5efcd9346d2acb4a4a969b45897dfe048b3bf0464617461f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50606020474786964a38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655604766f757421e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac94375e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46d05018057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5eedec3ebaa08fb010f2f96e17a0e039ad87fe60771a7301f8c5e88995d05676b0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e46ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb25050130a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe768f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffff000000000000f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7afba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da7801fdf0cf0dd76b6921b77cf7f07ec5efcd9346d2acb4a4a969b45897dfe048b3bf06030474797065853638fb1d1e26ae91f84a5d474a2e14756192d19a117bbf62679d6898a3274a077375627479706588ec906b4268285b161323d5b85da01d0e5dc939bb96fdfae1f004cb74403dd5076368617273657488ec906b4268285b161323d5b85da01d0e5dc939bb96fdfae1f004cb74403dd50000000001e4383a58b91eeafbec48c387fb18601ecdbfd2253ed700347486ecdeba469d2e00055247423231060f6174746163686d656e74547970657301086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c56840001076372656174656401596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b01000a656e67726176696e6773011392c3db98aa94654c635071e304e3e309a512a9a92998a83b94434dc876fd9f000104737065630199624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100057465726d730118cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010006746f6b656e7301dc87e7b9d1283426f5a64081bc65a706ad0ddc0149f615f624f24b60c2820e600001030a61737365744f776e6572051870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900000112696e666c6174696f6e416c6c6f77616e636505140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0100010b7570646174655269676874010100000001467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b050f6174746163686d656e745479706573000000ffff0763726561746564000100010004737065630001000100057465726d73000100010006746f6b656e73000000ffff030a61737365744f776e6572000000ffff12696e666c6174696f6e416c6c6f77616e6365000000ffff0b757064617465526967687400000001000004010304090407456e67726176650100010a656e67726176696e67730001000100010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000401020708010b62656e65666963696172790549737375650101467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b02126e65774174746163686d656e745479706573010f6174746163686d656e7454797065730000ffff096e6577546f6b656e730106746f6b656e730000ffff0104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff00050103040609010b62656e65666963696172790652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff0003010207010b62656e6566696369617279006b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de01085472616e7366657200cd894055e5040efd730dd590476931d6cfa823086d5c4dfc1396b37e0741ffa5e4383a58b91eeafbec48c387fb18601ecdbfd2253ed700347486ecdeba469d2e04d0070473706563d30707637265617465643508057465726d73360806746f6b656e7301a00f0a61737365744f776e657200011027085472616e7366657200000000cd894055e5040efd730dd590476931d6cfa823086d5c4dfc1396b37e0741ffa580000004d00701000c00044449424104444942410002d3070100040088cca56435080100060004004449424136080100400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e6700000001a00f020100030105b41f029f91e5fe7aaa5fdb48c840fb9fb67e3e6f448db96f87e88c3a9dd64d00000000b603038e127d7dcd0c000100000001000000000000000000000000000000000000000000"; From 5d27de8e2a86e538cbffb65ce908651053ced695 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 7 Jul 2023 18:30:31 -0600 Subject: [PATCH 14/15] Turn some unwraps into ? to better propagate errors instead of panics. --- src/bitcoin/psbt.rs | 5 +---- src/constants.rs | 2 +- src/rgb.rs | 19 ++++++++----------- src/rgb/contract.rs | 45 ++++++++++++++------------------------------- src/rgb/issue.rs | 31 +++++++++++-------------------- 5 files changed, 35 insertions(+), 67 deletions(-) diff --git a/src/bitcoin/psbt.rs b/src/bitcoin/psbt.rs index 8d4791ba..67ac7049 100644 --- a/src/bitcoin/psbt.rs +++ b/src/bitcoin/psbt.rs @@ -27,10 +27,7 @@ pub async fn sign_psbt( blockchain.broadcast(&tx).await?; let txid = tx.txid(); - let tx = blockchain - .get_tx(&txid) - .await - .expect("tx that was just broadcasted now exists"); + let tx = blockchain.get_tx(&txid).await?; let mut sent = 0; let mut received = 0; diff --git a/src/constants.rs b/src/constants.rs index 42532bc4..d46e528c 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -74,7 +74,7 @@ pub const NOSTR_PATH: &str = "m/44h/1237h/0h"; // Magic number for versioning descriptors pub const DIBA_DESCRIPTOR_VERSION: u8 = 0; -pub const DIBA_MAGIC_NO: [u8; 4] = [b'D', b'I', b'B', b'A']; +pub const DIBA_MAGIC_NO: [u8; 4] = *b"DIBA"; pub const DIBA_DESCRIPTOR: [u8; 5] = [ DIBA_MAGIC_NO[0], DIBA_MAGIC_NO[1], diff --git a/src/rgb.rs b/src/rgb.rs index a0da380f..e4fecae3 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -426,10 +426,7 @@ pub async fn transfer_asset(sk: &str, request: RgbTransferRequest) -> Result() - .expect("invalid transfer serialization") - .to_hex(), + consig: transfer.to_strict_serialized::()?.to_hex(), psbt: psbt_hex, commit: commit_hex, }; @@ -529,7 +526,7 @@ pub async fn list_contracts(sk: &str) -> Result { let mut contracts = vec![]; - for contract_id in stock.contract_ids().expect("invalid contracts state") { + for contract_id in stock.contract_ids()? { let resp = extract_contract_by_id(contract_id, &mut stock, &mut resolver, &mut wallet)?; contracts.push(resp); } @@ -548,10 +545,10 @@ pub async fn list_interfaces(sk: &str) -> Result { let stock = retrieve_stock(sk, ASSETS_STOCK).await?; let mut interfaces = vec![]; - for schema_id in stock.schema_ids().expect("invalid schemas state") { - let schema = stock.schema(schema_id).expect("invalid schemas state"); + for schema_id in stock.schema_ids()? { + let schema = stock.schema(schema_id)?; for (iface_id, iimpl) in schema.clone().iimpls.into_iter() { - let face = stock.iface_by_id(iface_id).expect("invalid iface state"); + let face = stock.iface_by_id(iface_id)?; let item = InterfaceDetail { name: face.name.to_string(), @@ -569,11 +566,11 @@ pub async fn list_schemas(sk: &str) -> Result { let stock = retrieve_stock(sk, ASSETS_STOCK).await?; let mut schemas = vec![]; - for schema_id in stock.schema_ids().expect("invalid schemas state") { - let schema = stock.schema(schema_id).expect("invalid schemas state"); + for schema_id in stock.schema_ids()? { + let schema = stock.schema(schema_id)?; let mut ifaces = vec![]; for (iface_id, _) in schema.clone().iimpls.into_iter() { - let face = stock.iface_by_id(iface_id).expect("invalid iface state"); + let face = stock.iface_by_id(iface_id)?; ifaces.push(face.name.to_string()); } schemas.push(SchemaDetail { diff --git a/src/rgb/contract.rs b/src/rgb/contract.rs index 392ac22a..2b2fefb6 100644 --- a/src/rgb/contract.rs +++ b/src/rgb/contract.rs @@ -55,12 +55,9 @@ where .expect("invalid contract data") .to_base32(), bech32::Variant::Bech32m, - ) - .expect("invalid contract data"); - let contract_strict = contract_bindle - .to_strict_serialized::<0xFFFFFF>() - .expect("invalid contract data") - .to_hex(); + )?; + + let contract_strict = contract_bindle.to_strict_serialized::<0xFFFFFF>()?.to_hex(); let contract_iface = stock .contract_iface(contract_bindle.contract_id(), iface_id.to_owned()) @@ -148,37 +145,24 @@ where for (index, (_, global_assign)) in contract_genesis.genesis.assignments.iter().enumerate() { let idx = index as u16; if global_assign.is_fungible() { - if let Some(reveal) = global_assign - .as_fungible_state_at(idx) - .expect("fail retrieve fungible data") - { + if let Some(reveal) = global_assign.as_fungible_state_at(idx)? { supply += reveal.value.as_u64(); } } else if global_assign.is_structured() - && global_assign - .as_structured_state_at(idx) - .expect("fail retrieve structured data") - .is_some() + && global_assign.as_structured_state_at(idx)?.is_some() { supply += 1; } } let genesis = contract_genesis.genesis.clone(); - let genesis_strict = genesis - .to_strict_serialized::<0xFFFFFF>() - .expect("invalid genesis data") - .to_hex(); + let genesis_strict = genesis.to_strict_serialized::<0xFFFFFF>()?.to_hex(); let genesis_legacy = encode( "rgb", - genesis - .to_strict_serialized::<0xFFFFFF>() - .expect("invalid contract data") - .to_base32(), + genesis.to_strict_serialized::<0xFFFFFF>()?.to_base32(), bech32::Variant::Bech32m, - ) - .expect("invalid contract data"); + )?; let genesis_formats = GenesisFormats { legacy: genesis_legacy, @@ -190,7 +174,10 @@ where let mut meta = none!(); let ty: FieldName = FieldName::from("tokens"); if contract_iface.global(ty.clone()).is_ok() { - let type_id = contract_iface.iface.global_type(&ty).expect(""); + let type_id = contract_iface + .iface + .global_type(&ty) + .expect("no global type id"); let type_schema = contract_iface .state @@ -217,16 +204,12 @@ where if let Some(preview) = token_data.preview { media = MediaInfo { ty: preview.ty.to_string(), - source: String::from_utf8(preview.data.to_inner()).expect("invalid data"), + source: String::from_utf8(preview.data.to_inner())?, }; } let single = ContractMetadata::UDA(UDADetail { - token_index: token_data - .index - .to_string() - .parse() - .expect("invalid token_index"), + token_index: token_data.index.to_string().parse()?, ticker: ticker.clone(), name: name.clone(), description: description.clone(), diff --git a/src/rgb/issue.rs b/src/rgb/issue.rs index 317cd216..dcdeea6b 100644 --- a/src/rgb/issue.rs +++ b/src/rgb/issue.rs @@ -50,16 +50,12 @@ where T: ResolveHeight + ResolveTx, T::Error: 'static, { - let iface_name = match TypeName::from_str(iface) { - Ok(name) => name, - _ => return Err(IssueError::Forge(BuilderError::InterfaceMismatch)), - }; + let iface_name = TypeName::from_str(iface) + .map_err(|_| IssueError::Forge(BuilderError::InterfaceMismatch))?; - let binding = stock.to_owned(); - let iface = match binding.iface_by_name(&iface_name) { - Ok(name) => name, - _ => return Err(IssueError::Forge(BuilderError::InterfaceMismatch)), - }; + let iface = stock + .iface_by_name(&iface_name) + .map_err(|_| IssueError::Forge(BuilderError::InterfaceMismatch))?; if ticker.len() < 3 || ticker.len() > 8 || ticker.chars().any(|c| c < 'A' && c > 'Z') { return Err(IssueError::InvalidTicker("Ticker must be between 3 and 8 chars, contain no spaces and consist only of capital letters".to_string())); @@ -82,21 +78,16 @@ where _ => return Err(IssueError::ContractNotfound(iface.name.to_string())), }; - let resp = match contract_issued { - Ok(resp) => resp, - Err(err) => return Err(IssueError::Forge(err)), - }; + let resp = contract_issued.map_err(IssueError::Forge)?; + let contract_id = resp.contract_id().to_string(); - let resp = match resp.clone().validate(resolver) { - Ok(resp) => resp, - Err(_err) => return Err(IssueError::ContractInvalid(resp.contract_id().to_string())), - }; + let resp = resp + .validate(resolver) + .map_err(|_| IssueError::ContractInvalid(contract_id.clone()))?; stock .import_contract(resp.clone(), resolver) - .or(Err(IssueError::ImportContract( - resp.contract_id().to_string(), - )))?; + .or(Err(IssueError::ImportContract(contract_id)))?; Ok(resp) } From baf434d599b3a8c9ba9e9b99205c64d879eb887b Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Mon, 10 Jul 2023 09:55:30 -0300 Subject: [PATCH 15/15] chor: bump strict-types to 1.4.1 --- Cargo.lock | 8 ++++---- Cargo.toml | 4 ++-- tests/rgb.rs | 11 +++++------ tests/rgb/sre/st140.rs | 2 +- tests/rgb/sre/st140_web.rs | 2 +- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 89d6a839..64119950 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3219,9 +3219,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "strict_encoding" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca43fabd13842577ce6d152047796794e209625ff89d3f2434d99b742eea1c98" +checksum = "0b91c4bf53aea24d7507b2704f326d8771ab1c543c343094df192b4b14cada60" dependencies = [ "amplify", "half 2.3.1", @@ -3244,9 +3244,9 @@ dependencies = [ [[package]] name = "strict_types" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b1669bdf556c9a00a6a9aa9bf76d3ebec83aa4aa3e178bdfd2073157564579" +checksum = "b0c26d9118e98e0e21b65fab39098d76c20197f1f6cd6b82344a119cdf9d0b13" dependencies = [ "amplify", "baid58", diff --git a/Cargo.toml b/Cargo.toml index 745dbf2b..a312f970 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,8 +83,8 @@ serde = "1.0.152" serde_json = "1.0.91" postcard = { version = "1.0.4", features = ["alloc"] } serde-encrypt = "0.7.0" -strict_types = "1.4.0" -strict_encoding = "~2.4.0" +strict_types = "1.4.1" +strict_encoding = "2.4.1" tokio = { version = "1.28.2", features = ["macros", "sync"] } [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/tests/rgb.rs b/tests/rgb.rs index 36af1c6b..ae6205e5 100644 --- a/tests/rgb.rs +++ b/tests/rgb.rs @@ -13,14 +13,13 @@ mod rgb { // mod collectibles; mod collectibles; + mod fungibles; mod import; mod issue; - // TODO: Uncomment after fixing slow encoding/decoding of strict type - // mod fungibles; - // mod states; - // mod stress; - // mod transfers; - // mod udas; + mod states; + mod stress; + mod transfers; + mod udas; pub mod utils; mod watcher; } diff --git a/tests/rgb/sre/st140.rs b/tests/rgb/sre/st140.rs index d763526f..05eaa586 100644 --- a/tests/rgb/sre/st140.rs +++ b/tests/rgb/sre/st140.rs @@ -17,7 +17,7 @@ use percent_encoding::utf8_percent_encode; use reqwest::Client; #[tokio::test] -#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.4.0)"] +#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.4.x)"] async fn allow_re_issue_rgb_contracts() -> anyhow::Result<()> { let bitmask_endpoint = BITMASK_ENDPOINT.read().await.to_string(); let issuer_keys = save_mnemonic( diff --git a/tests/rgb/sre/st140_web.rs b/tests/rgb/sre/st140_web.rs index e3059b82..daac5794 100644 --- a/tests/rgb/sre/st140_web.rs +++ b/tests/rgb/sre/st140_web.rs @@ -32,7 +32,7 @@ use wasm_bindgen_test::*; wasm_bindgen_test_configure!(run_in_browser); // #[wasm_bindgen_test] -#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.4.0)"] +#[ignore = "No longer necessary running always, only to check re-issue operation (strict-type 1.4.x)"] async fn allow_re_issue_rgb_contracts() -> anyhow::Result<()> { set_panic_hook(); let mnemonic = env!("TEST_WALLET_SEED", "TEST_WALLET_SEED variable not set");