From 3093b3340827b8b7aada02042c8fa4b3294cf20a Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Fri, 23 Jun 2023 17:58:53 -0300 Subject: [PATCH 01/27] feat: bump rgb version --- Cargo.lock | 630 +++++++++++++++----------------- Cargo.toml | 30 +- src/rgb/contract.rs | 4 +- src/rgb/resolvers.rs | 1 - src/rgb/structs.rs | 11 +- src/rgb/wallet.rs | 17 +- tests/rgb.rs | 3 +- tests/rgb/integration/import.rs | 244 ++----------- tests/rgb/integration/states.rs | 250 +++++++++++++ 9 files changed, 616 insertions(+), 574 deletions(-) create mode 100644 tests/rgb/integration/states.rs diff --git a/Cargo.lock b/Cargo.lock index adac96ca..69756e73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,20 +36,20 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ "cfg-if", "cipher 0.4.4", - "cpufeatures 0.2.7", + "cpufeatures 0.2.8", ] [[package]] name = "aes-gcm" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" +checksum = "209b47e8954a928e1d72e86eca7000ebb6655fe1436d33eefc2201cad027e237" dependencies = [ "aead 0.5.2", "aes", @@ -61,26 +61,26 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] [[package]] name = "aluvm" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ebb162f495c9b467476c4287fbdf5afaf816a9c91c7e37de9d0ff13804ef502" +checksum = "6385af946e0be015f5e1ca29c5e69c1ed455e6d955e0ba05db8537e666c144ea" dependencies = [ "amplify", "baid58", - "bitcoin_hashes 0.12.0", - "blake3", - "half 2.2.1", + "half 2.3.0", "paste", + "ripemd", "serde", + "sha2 0.10.7", "strict_encoding", "strict_types", ] @@ -111,7 +111,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5b7f29fad2a3def5dfbfed0da85b886eb927a18fe0296c06e39880b7a96db05" dependencies = [ "amplify_num", - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -158,6 +158,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -192,9 +198,9 @@ checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "ascii" @@ -213,7 +219,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.22", ] [[package]] @@ -261,7 +267,7 @@ checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes", "futures-util", "headers", @@ -312,14 +318,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.22", ] [[package]] name = "baid58" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dce38f6b284b55ab61c1efe2143ac5ca2fcc6090536884e55921f4e002894de" +checksum = "29eb856caa83b642563396407c1deb5331acd62d9d91cd5a5d0dcab4a825ad4b" dependencies = [ "base58", "blake3", @@ -351,9 +357,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "base64-compat" @@ -549,11 +555,16 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded" + [[package]] name = "bitmask-core" version = "0.6.0-rc.2" dependencies = [ - "aluvm", "amplify", "anyhow", "argon2", @@ -581,7 +592,7 @@ dependencies = [ "gloo-console", "gloo-net", "hex", - "indexmap", + "indexmap 1.9.3", "inflate", "js-sys", "lightning-invoice", @@ -631,21 +642,21 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] name = "blake3" -version = "1.3.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef" +checksum = "729b71f35bd3fa1a4c86b85d32c8b9069ea7fe14f7a53cfabb65f62d4265b888" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -677,9 +688,9 @@ dependencies = [ [[package]] name = "bp-core" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77895cc1d62865613d3c2aa0331de273974c4901fe00ecbdbd51fe69337a9bda" +checksum = "20eee52cf1c0d1fb6820436cd73b709483a14257fcb66753b0002d5f61151d88" dependencies = [ "amplify", "bp-dbc", @@ -694,9 +705,9 @@ dependencies = [ [[package]] name = "bp-dbc" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa85f689829ecbb13f56cc9e06ebf3c101bdd4df85fc10049df080f997020e26" +checksum = "9e93be8147fe47376f1144a78b6e4cf11999efa8328fcca1b25b7f030491bb27" dependencies = [ "amplify", "baid58", @@ -709,9 +720,9 @@ dependencies = [ [[package]] name = "bp-primitives" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e69ae41e82b139784dc3fd8318a8a892d75300954c6bfc0ab16c4a056745602" +checksum = "52baa67a14cf94e4e35c1f279b2b8bdac342e2a6a3e57afd8887d46855d8d0b9" dependencies = [ "amplify", "commit_verify", @@ -723,9 +734,9 @@ dependencies = [ [[package]] name = "bp-seals" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3380f6c3cb42f4ebf3b39bde6239381481097d70594729f630db46c3bee9b0" +checksum = "2f5b4ab2ba908733c37d4259474920c87b31d69453c3acd59298bf1d69e59392" dependencies = [ "amplify", "baid58", @@ -740,9 +751,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.2" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byteorder" @@ -826,13 +837,13 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", "serde", "time 0.1.45", @@ -880,14 +891,15 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1baccabac24e468b317b3a627fa0a07e2708f9efbad2d1b44eb64fe993f7c621" +checksum = "395d2cf275f1359bf36f26e15f68d2be5edc16fe0b210bc47ad9d6cefc1a3c5f" dependencies = [ "amplify", "commit_encoding_derive", "rand", "serde", + "sha2 0.10.7", "strict_encoding", "strict_types", ] @@ -904,9 +916,9 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" [[package]] name = "core-foundation" @@ -935,9 +947,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" dependencies = [ "libc", ] @@ -1042,7 +1054,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.15", + "syn 2.0.22", ] [[package]] @@ -1053,14 +1065,14 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" dependencies = [ "darling_core", "quote", - "syn 2.0.15", + "syn 2.0.22", ] [[package]] name = "data-encoding" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "deflate" @@ -1115,9 +1127,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "crypto-common", @@ -1135,7 +1147,7 @@ dependencies = [ "hkdf", "libsecp256k1", "rand", - "sha2 0.10.6", + "sha2 0.10.7", "typenum", ] @@ -1180,6 +1192,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + [[package]] name = "errno" version = "0.3.1" @@ -1250,7 +1268,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1276,9 +1294,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -1339,7 +1357,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.22", ] [[package]] @@ -1420,14 +1438,15 @@ dependencies = [ [[package]] name = "gloo-net" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" +checksum = "3000ef231a67d5bfee6b35f2c0f6f5c8d45b3381ef5bbbea603690ec4e539762" dependencies = [ "futures-channel", "futures-core", "futures-sink", "gloo-utils", + "http", "js-sys", "pin-project", "serde", @@ -1452,9 +1471,9 @@ dependencies = [ [[package]] name = "gloo-utils" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5" +checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" dependencies = [ "js-sys", "serde", @@ -1475,7 +1494,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -1490,10 +1509,11 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "half" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +checksum = "9906a89f1724975a455316ae0554ceaa45ad83bb336f1125a87bfbdb9197cfa0" dependencies = [ + "cfg-if", "crunchy", ] @@ -1512,6 +1532,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "headers" version = "0.3.8" @@ -1519,7 +1545,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" dependencies = [ "base64 0.13.1", - "bitflags", + "bitflags 1.3.2", "bytes", "headers-core", "http", @@ -1618,7 +1644,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -1713,15 +1739,15 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.2" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" dependencies = [ "http", "hyper", - "rustls 0.20.8", + "rustls", "tokio", - "tokio-rustls 0.23.4", + "tokio-rustls", ] [[package]] @@ -1739,9 +1765,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1768,9 +1794,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1783,10 +1809,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "inflate" version = "0.4.5" @@ -1820,9 +1856,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", @@ -1855,9 +1891,9 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -1870,9 +1906,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libsecp256k1" @@ -1947,15 +1983,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -1963,12 +1999,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "matchit" @@ -2015,14 +2048,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -2070,7 +2102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a38ff6fec17be97b6ea1e30a4913618c8e02b2e555b5188d01668f2e4fa09507" dependencies = [ "aes", - "base64 0.21.0", + "base64 0.21.2", "bech32", "bip39", "bitcoin 0.30.0", @@ -2110,25 +2142,15 @@ dependencies = [ "futures-util", "thiserror", "tokio", - "tokio-rustls 0.24.0", + "tokio-rustls", "tokio-socks", "tokio-tungstenite", "url", "webpki", - "webpki-roots 0.23.0", + "webpki-roots 0.23.1", "ws_stream_wasm", ] -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.15" @@ -2150,9 +2172,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opaque-debug" @@ -2162,11 +2184,11 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.52" +version = "0.10.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "foreign-types", "libc", @@ -2183,7 +2205,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.22", ] [[package]] @@ -2194,9 +2216,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.87" +version = "0.9.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" dependencies = [ "cc", "libc", @@ -2216,15 +2238,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-targets", ] [[package]] @@ -2259,9 +2281,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "percent-encoding-rfc3986" @@ -2281,22 +2303,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] @@ -2323,21 +2345,21 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ - "cpufeatures 0.2.7", + "cpufeatures 0.2.8", "opaque-debug", - "universal-hash 0.4.1", + "universal-hash 0.4.0", ] [[package]] name = "polyval" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" +checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" dependencies = [ "cfg-if", - "cpufeatures 0.2.7", + "cpufeatures 0.2.8", "opaque-debug", - "universal-hash 0.5.0", + "universal-hash 0.5.1", ] [[package]] @@ -2395,9 +2417,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] @@ -2427,9 +2449,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -2470,29 +2492,20 @@ dependencies = [ "getrandom", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - [[package]] name = "redox_syscall" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.8.1" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", @@ -2501,17 +2514,17 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "reqwest" -version = "0.11.17" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", "bytes", "encoding_rs", "futures-core", @@ -2530,14 +2543,14 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.20.8", + "rustls", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", "tokio-native-tls", - "tokio-rustls 0.23.4", + "tokio-rustls", "tokio-socks", "tower-service", "url", @@ -2550,8 +2563,8 @@ dependencies = [ [[package]] name = "rgb-contracts" -version = "0.10.0" -source = "git+https://github.com/crisdut/rgb?branch=exp/fixies#9998c63702b2b139b37c7f1310c90672ce9b9c53" +version = "0.10.0-beta.2" +source = "git+https://github.com/crisdut/rgb?branch=release/bmc-v0.6#e5090e428a0bc9369877fa0fe39e8dcee857f3c7" dependencies = [ "amplify", "baid58", @@ -2570,9 +2583,9 @@ dependencies = [ [[package]] name = "rgb-core" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f265335d2ea2ac9b36f52cf7b34e0aaa10e48e502d56111d4dde0b6edf98647" +checksum = "5ff930c654b3fb0d547e64188c0197c45749c1d3b86af4ab768f4576f238c12d" dependencies = [ "aluvm", "amplify", @@ -2592,7 +2605,7 @@ dependencies = [ [[package]] name = "rgb-persist-fs" version = "0.10.0" -source = "git+https://github.com/crisdut/rgb?branch=exp/fixies#9998c63702b2b139b37c7f1310c90672ce9b9c53" +source = "git+https://github.com/crisdut/rgb?branch=release/bmc-v0.6#e5090e428a0bc9369877fa0fe39e8dcee857f3c7" dependencies = [ "amplify", "rgb-std", @@ -2602,7 +2615,7 @@ dependencies = [ [[package]] name = "rgb-schemata" version = "0.10.0-beta.1" -source = "git+https://github.com/crisdut/rgbsc?branch=exp/full-uda#8601931000b66d994e420a927807e504979e49f7" +source = "git+https://github.com/crisdut/rgbsc?branch=release/bmc-v0.6#3ba61ba7827e8018f05b9c0dfd126e75eb7deb7f" dependencies = [ "aluvm", "amplify", @@ -2617,11 +2630,11 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.10.2" -source = "git+https://github.com/crisdut/rgb-wallet?branch=exp/full-uda#4a151c049b97da5adf3e433ef7ac9362bb57e82e" +source = "git+https://github.com/crisdut/rgb-wallet?branch=release/bmc-v0.6#3c4b0e719a5c90b4f8cbb67f59cd586060c597ae" dependencies = [ "amplify", "baid58", - "base64 0.21.0", + "base64 0.21.2", "bp-core", "commit_verify", "getrandom", @@ -2635,7 +2648,7 @@ dependencies = [ [[package]] name = "rgb-wallet" version = "0.10.2" -source = "git+https://github.com/crisdut/rgb-wallet?branch=exp/full-uda#4a151c049b97da5adf3e433ef7ac9362bb57e82e" +source = "git+https://github.com/crisdut/rgb-wallet?branch=release/bmc-v0.6#3c4b0e719a5c90b4f8cbb67f59cd586060c597ae" dependencies = [ "amplify", "baid58", @@ -2645,7 +2658,7 @@ dependencies = [ "commit_verify", "fluent-uri", "getrandom", - "indexmap", + "indexmap 1.9.3", "percent-encoding", "rgb-core", "rgb-std", @@ -2668,6 +2681,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rustc_version" version = "0.4.0" @@ -2679,11 +2701,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -2693,21 +2715,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" -dependencies = [ - "log", - "ring", - "sct", - "webpki", -] - -[[package]] -name = "rustls" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" +checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" dependencies = [ "log", "ring", @@ -2721,7 +2731,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", ] [[package]] @@ -2854,11 +2864,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2855b3715770894e67cbfa3df957790aa0c9edc3bf06efa1a84d77fa0839d1" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -2889,9 +2899,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] @@ -2949,20 +2959,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.22", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa", "ryu", @@ -2980,9 +2990,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -3018,11 +3028,11 @@ dependencies = [ "base64 0.13.1", "chrono", "hex", - "indexmap", + "indexmap 1.9.3", "serde", "serde_json", "serde_with_macros", - "time 0.3.21", + "time 0.3.22", ] [[package]] @@ -3034,16 +3044,16 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.22", ] [[package]] name = "serde_yaml" -version = "0.9.21" +version = "0.9.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" +checksum = "452e67b9c20c37fa79df53201dc03839651086ed9bbe92b3ca585ca9fdaa7d85" dependencies = [ - "indexmap", + "indexmap 2.0.0", "itoa", "ryu", "serde", @@ -3057,8 +3067,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", - "cpufeatures 0.2.7", - "digest 0.10.6", + "cpufeatures 0.2.8", + "digest 0.10.7", ] [[package]] @@ -3069,20 +3079,20 @@ checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if", - "cpufeatures 0.2.7", + "cpufeatures 0.2.8", "digest 0.9.0", "opaque-debug", ] [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", - "cpufeatures 0.2.7", - "digest 0.10.6", + "cpufeatures 0.2.8", + "digest 0.10.7", ] [[package]] @@ -3189,12 +3199,12 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "strict_encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fff0b729ca136cddccc87481dd932a442133a12a490f349d67f5d4c20b421e5" +checksum = "0be9dd3df80dc083d4e20ac87246a67f42b3a5016375ae5a48f292e85ccfb1bd" dependencies = [ "amplify", - "half 2.2.1", + "half 2.3.0", "serde", "strict_encoding_derive", ] @@ -3214,21 +3224,22 @@ dependencies = [ [[package]] name = "strict_types" -version = "1.2.0" -source = "git+https://github.com/crisdut/strict-types/?branch=fix/typelib-id#74106e3554a2af646bf9220dd19396fc0cb1e90c" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e611df6ed5752860c760c94509b838cd225e9e9e5de301517db195cf6f1f2cd" dependencies = [ "amplify", "baid58", - "base64 0.21.0", - "blake3", - "half 2.2.1", - "indexmap", + "base64 0.21.2", + "half 2.3.0", + "indexmap 1.9.3", "serde", "serde_json", "serde_with", "serde_yaml", + "sha2 0.10.7", "strict_encoding", - "toml 0.7.3", + "toml 0.7.5", ] [[package]] @@ -3249,9 +3260,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" @@ -3266,9 +3277,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" dependencies = [ "proc-macro2", "quote", @@ -3283,15 +3294,16 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "redox_syscall", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -3320,7 +3332,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.22", ] [[package]] @@ -3336,9 +3348,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ "itoa", "serde", @@ -3403,7 +3415,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.22", ] [[package]] @@ -3418,22 +3430,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.23.4" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.20.8", - "tokio", - "webpki", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" -dependencies = [ - "rustls 0.21.1", + "rustls", "tokio", ] @@ -3457,11 +3458,11 @@ checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c" dependencies = [ "futures-util", "log", - "rustls 0.21.1", + "rustls", "tokio", - "tokio-rustls 0.24.0", + "tokio-rustls", "tungstenite", - "webpki-roots 0.23.0", + "webpki-roots 0.23.1", ] [[package]] @@ -3489,9 +3490,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" dependencies = [ "serde", "serde_spanned", @@ -3501,20 +3502,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" dependencies = [ - "indexmap", + "indexmap 2.0.0", "serde", "serde_spanned", "toml_datetime", @@ -3539,11 +3540,11 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658" +checksum = "a8bd22a874a2d0b70452d5597b12c537331d49060824a95f49f108994f94aa4c" dependencies = [ - "bitflags", + "bitflags 2.3.2", "bytes", "futures-core", "futures-util", @@ -3607,7 +3608,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls 0.21.1", + "rustls", "sha1", "thiserror", "url", @@ -3629,9 +3630,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-normalization" @@ -3644,9 +3645,9 @@ dependencies = [ [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" dependencies = [ "generic-array", "subtle", @@ -3654,9 +3655,9 @@ dependencies = [ [[package]] name = "universal-hash" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", "subtle", @@ -3676,28 +3677,28 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "ureq" -version = "2.6.2" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d" +checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9" dependencies = [ - "base64 0.13.1", + "base64 0.21.2", "flate2", "log", "once_cell", - "rustls 0.20.8", + "rustls", + "rustls-webpki", "serde", "serde_json", "socks", "url", - "webpki", - "webpki-roots 0.22.6", + "webpki-roots 0.23.1", ] [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -3725,11 +3726,10 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -3747,9 +3747,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "serde", @@ -3759,24 +3759,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.22", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.36" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -3786,9 +3786,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3796,28 +3796,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.22", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-bindgen-test" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e636f3a428ff62b3742ebc3c70e254dfe12b8c2b469d688ea59cdd4abcf502" +checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" dependencies = [ "console_error_panic_hook", "js-sys", @@ -3829,9 +3829,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f18c1fad2f7c4958e7bcce014fa212f59a65d5e3721d0f77e6c0b27ede936ba3" +checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" dependencies = [ "proc-macro2", "quote", @@ -3839,9 +3839,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -3868,9 +3868,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa54963694b65584e170cf5dc46aeb4dcaa5584e652ff5f3952e56d66aff0125" +checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" dependencies = [ "rustls-webpki", ] @@ -3912,7 +3912,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.0", + "windows-targets", ] [[package]] @@ -3930,37 +3930,13 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -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", + "windows-targets", ] [[package]] @@ -4064,9 +4040,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" dependencies = [ "memchr", ] @@ -4141,7 +4117,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.22", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8900e74d..db0baeb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ server = ["tokio/full", "tower-http/cors"] [dependencies] anyhow = "1.0.71" -aluvm = "0.10.2" amplify = "4.0.0" argon2 = "0.5.0" base64 = { package = "base64-compat", version = "1.0.0" } @@ -39,9 +38,9 @@ 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.3" -commit_verify = "0.10.2" -bp-seals = "0.10.3" +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" console_error_panic_hook = "0.1.7" @@ -74,18 +73,22 @@ psbt = { version = "0.10.0-alpha.2", features = [ ] } regex = "1.7.0" reqwest = { version = "0.11.16", features = ["json"] } -rgb-contracts = { version = "0.10.0", default-features = false, features = [ +rgb-contracts = { version = "0.10.0-beta.2", default-features = false, features = [ "log", ] } -rgb-std = { version = "0.10.2" } 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.2.0" -strict_encoding = "2.2.0" +strict_types = "1.3.0" +strict_encoding = "2.3.0" tokio = { version = "1.28.2", features = ["macros", "sync"] } [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -94,7 +97,7 @@ bdk = { version = "0.28.0", features = [ "async-interface", ], default-features = false } gloo-console = "0.2.3" -gloo-net = "0.2.6" +gloo-net = "0.3.0" js-sys = "0.3.63" serde-wasm-bindgen = "0.5.0" wasm-bindgen = { version = "0.2.86", features = ["serde-serialize"] } @@ -124,14 +127,13 @@ wasm-bindgen-test = "0.3.36" [patch.crates-io] # TODO: Remove this after merge and release fixies -rgb-contracts = { git = "https://github.com/crisdut/rgb", branch = "exp/fixies" } bitcoin_scripts = { git = "https://github.com/crisdut/bp-foundation", branch = "release/0.10.0-alpha.2" } bitcoin_blockchain = { git = "https://github.com/crisdut/bp-foundation", branch = "release/0.10.0-alpha.2" } -strict_types = { git = "https://github.com/crisdut/strict-types/", branch = "fix/typelib-id" } # TODO: Remove this after propose a universal tweak in descriptor-wallet descriptor-wallet = { git = "https://github.com/crisdut/descriptor-wallet", branch = "exp/tapret-transfers" } psbt = { git = "https://github.com/crisdut/descriptor-wallet", branch = "exp/tapret-transfers" } # TODO: Remove this after merge and release fixies -rgb-schemata = { git = "https://github.com/crisdut/rgbsc", branch = "exp/full-uda" } -rgb-wallet = { git = "https://github.com/crisdut/rgb-wallet", branch = "exp/full-uda" } -rgb-std = { git = "https://github.com/crisdut/rgb-wallet", branch = "exp/full-uda" } +rgb-contracts = { git = "https://github.com/crisdut/rgb", branch = "release/bmc-v0.6" } +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" } diff --git a/src/rgb/contract.rs b/src/rgb/contract.rs index b12a4bac..a4738621 100644 --- a/src/rgb/contract.rs +++ b/src/rgb/contract.rs @@ -11,6 +11,7 @@ use rgbstd::{ use strict_encoding::{FieldName, StrictDeserialize, StrictSerialize}; use strict_types::StrictVal; +use crate::rgb::structs::EmptyFilter; use crate::structs::{ AllocationValue, ContractFormats, ContractMeta, ContractMetadata, ContractResponse, MediaInfo, UDADetail, @@ -111,8 +112,9 @@ pub fn extract_contract_by_id( }; } + let empty = EmptyFilter {}; for owned in &contract_iface.iface.assignments { - if let Ok(allocations) = contract_iface.fungible(owned.name.clone()) { + if let Ok(allocations) = contract_iface.fungible(owned.name.clone(), Some(&empty)) { for allocation in allocations { supply = allocation.value; } diff --git a/src/rgb/resolvers.rs b/src/rgb/resolvers.rs index 060f0a4f..8307cba1 100644 --- a/src/rgb/resolvers.rs +++ b/src/rgb/resolvers.rs @@ -54,7 +54,6 @@ impl rgb::Resolver for ExplorerResolver { .position(|txout| txout.scriptpubkey == script); if let Some(index) = index { let index = index; - let status = match tx.status.block_height { Some(height) => MiningStatus::Blockchain(height), _ => MiningStatus::Mempool, diff --git a/src/rgb/structs.rs b/src/rgb/structs.rs index 6b054d2b..dba2c513 100644 --- a/src/rgb/structs.rs +++ b/src/rgb/structs.rs @@ -2,7 +2,9 @@ use std::{collections::HashMap, str::FromStr}; use bitcoin::Address; use bitcoin_scripts::address::AddressCompat; -use rgb::{RgbWallet, TerminalPath}; +use bp::Outpoint; +use rgb::{interface::OutpointFilter, RgbWallet, TerminalPath}; + use serde::{Deserialize, Serialize}; #[derive(Clone, PartialEq, Eq, Hash, Debug, Display)] @@ -38,3 +40,10 @@ 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 aa4ca716..16d63279 100644 --- a/src/rgb/wallet.rs +++ b/src/rgb/wallet.rs @@ -18,6 +18,7 @@ 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}; @@ -152,18 +153,22 @@ pub fn sync_wallet(iface_index: u32, wallet: &mut RgbWallet, resolver: &mut impl let step = 20; let index = 0; - // loop { let scripts = wallet.descr.derive(iface_index, index..step); - let new_scripts = scripts.into_iter().map(|(d, sc)| (d, sc)).collect(); + let new_scripts = scripts + .into_iter() + .map(|(d, sc)| { + // Reconstruct Taptree + + (d, sc) + }) + .collect(); let mut new_utxos = resolver .resolve_utxo(new_scripts) .expect("service unavalible"); if !new_utxos.is_empty() { wallet.utxos.append(&mut new_utxos); - // index += step; } - // } } pub fn register_address( @@ -236,7 +241,6 @@ pub fn list_allocations( iface_index: u32, resolver: &mut impl Resolver, ) -> Result, anyhow::Error> { - // TODO: Workaround let iface_name = match iface_index { 20 => "RGB20", 21 => "RGB21", @@ -244,13 +248,14 @@ pub fn list_allocations( }; 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()) { + if let Ok(allocations) = contract.fungible(owned.name.clone(), Some(&empty)) { for allocation in allocations { if let Some(utxo) = wallet.utxo(allocation.owner) { owners.push(AllocationDetail { diff --git a/tests/rgb.rs b/tests/rgb.rs index aada2675..af1ef36a 100644 --- a/tests/rgb.rs +++ b/tests/rgb.rs @@ -13,12 +13,13 @@ mod rgb { // mod collectibles; mod collectibles; mod fungibles; - mod import; mod issue; + mod states; mod stress; mod udas; pub mod utils; mod watcher; + mod import; } mod web { diff --git a/tests/rgb/integration/import.rs b/tests/rgb/integration/import.rs index 58dc8eae..04ffb29c 100644 --- a/tests/rgb/integration/import.rs +++ b/tests/rgb/integration/import.rs @@ -1,250 +1,48 @@ #![cfg(not(target_arch = "wasm32"))] +use crate::rgb::integration::utils::ISSUER_MNEMONIC; use bitmask_core::{ - bitcoin::{save_mnemonic, sign_psbt_file}, - rgb::{accept_transfer, create_watcher, get_contract}, - structs::{AcceptRequest, DecryptedWalletData, SecretString, SignPsbtRequest, WatcherRequest}, -}; - -use crate::rgb::integration::utils::{ - create_new_invoice, create_new_psbt, create_new_transfer, get_uda_data, import_new_contract, - issuer_issue_contract, ISSUER_MNEMONIC, OWNER_MNEMONIC, + bitcoin::save_mnemonic, + rgb::import, + structs::{AssetType, ImportRequest, SecretString}, }; #[tokio::test] async fn allow_import_fungible_contract() -> anyhow::Result<()> { - let issuer_resp = issuer_issue_contract("RGB20", 5, false, true, None).await; - assert!(issuer_resp.is_ok()); - - let import_resp = import_new_contract(issuer_resp?).await; - assert!(import_resp.is_ok()); - Ok(()) -} - -#[tokio::test] -async fn allow_import_uda_contract() -> anyhow::Result<()> { - let single = Some(get_uda_data()); - let issuer_resp = issuer_issue_contract("RGB21", 1, false, true, single).await; - assert!(issuer_resp.is_ok()); - - let import_resp = import_new_contract(issuer_resp?).await; - assert!(import_resp.is_ok()); - Ok(()) -} - -// TODO: Review after support multi-token transfer -// async fn _allow_import_collectible_contract() -> anyhow::Result<()> { -// let collectibles = Some(get_collectible_data()); -// let issuer_resp = issuer_issue_contract("RGB21", 1, false, true, collectibles).await; -// assert!(issuer_resp.is_ok()); - -// let import_resp = import_new_contract(issuer_resp?).await; -// assert!(import_resp.is_ok()); -// Ok(()) -// } - -#[tokio::test] -async fn allow_get_fungible_contract_state_by_accept_cosign() -> anyhow::Result<()> { - // 1. Issue and Generate Trasnfer (Issuer side) - let issuer_keys: DecryptedWalletData = save_mnemonic( + let issuer_keys = save_mnemonic( &SecretString(ISSUER_MNEMONIC.to_string()), &SecretString("".to_string()), ) .await?; - let owner_keys = save_mnemonic( - &SecretString(OWNER_MNEMONIC.to_string()), - &SecretString("".to_string()), - ) - .await?; - let issuer_resp = issuer_issue_contract("RGB20", 5, false, true, None).await?; - let owner_resp = create_new_invoice(issuer_resp.clone(), None).await?; - let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer_resp.clone()).await?; - let transfer_resp = &create_new_transfer(issuer_keys.clone(), owner_resp, psbt_resp).await?; - - // 2. Sign and Publish TX (Issuer side) - let issuer_sk = issuer_keys.private.nostr_prv.to_string(); - let owner_sk = owner_keys.private.nostr_prv.to_string(); - let request = SignPsbtRequest { - psbt: transfer_resp.psbt.clone(), - descriptor: SecretString(issuer_keys.private.rgb_assets_descriptor_xprv.clone()), - }; - let resp = sign_psbt_file(request).await; - assert!(resp.is_ok()); - - // 3. Accept Consig (Issuer Side) - let request = AcceptRequest { - consignment: transfer_resp.clone().consig, - force: false, - }; - let resp = accept_transfer(&issuer_sk, request).await; - assert!(resp.is_ok()); - assert!(resp?.valid); - - // 4. Accept Consig (Owner Side) - let request = AcceptRequest { - consignment: transfer_resp.consig.clone(), - force: false, - }; - let resp = accept_transfer(&owner_sk, request).await; - assert!(resp.is_ok()); - assert!(resp?.valid); - - // 5. Retrieve Contract (Issuer Side) - let contract_id = &issuer_resp.contract_id; - let resp = get_contract(&issuer_sk, contract_id).await; - assert!(resp.is_ok()); - assert_eq!(4, resp?.balance); - // 6. Create Watcher (Owner Side) - let watcher_name = "default"; - let create_watch_req = WatcherRequest { - name: watcher_name.to_string(), - xpub: owner_keys.public.watcher_xpub.clone(), - force: true, + let sk = &issuer_keys.private.nostr_prv; + let contract_import = ImportRequest { + import: AssetType::RGB20, + data: FUNGIBLE_CONTRACT.to_string(), }; - create_watcher(&owner_sk, create_watch_req).await?; - - // 7. Retrieve Contract (Owner Side) - let contract_id = &issuer_resp.contract_id; - let resp = get_contract(&owner_sk, contract_id).await; - assert!(resp.is_ok()); - assert_eq!(1, resp?.balance); + let import_resp = import(sk, contract_import).await; + assert!(import_resp.is_ok()); Ok(()) } #[tokio::test] -async fn allow_get_uda_contract_state_by_accept_cosign() -> anyhow::Result<()> { - // 1. Issue and Generate Trasnfer (Issuer side) - let single = Some(get_uda_data()); - let issuer_keys: DecryptedWalletData = save_mnemonic( +async fn allow_import_uda_contract() -> anyhow::Result<()> { + let issuer_keys = save_mnemonic( &SecretString(ISSUER_MNEMONIC.to_string()), &SecretString("".to_string()), ) .await?; - let owner_keys = save_mnemonic( - &SecretString(OWNER_MNEMONIC.to_string()), - &SecretString("".to_string()), - ) - .await?; - - let issuer_resp = issuer_issue_contract("RGB21", 1, false, true, single).await?; - let owner_resp = create_new_invoice(issuer_resp.clone(), None).await?; - let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer_resp.clone()).await?; - let transfer_resp = &create_new_transfer(issuer_keys.clone(), owner_resp, psbt_resp).await?; - - // 2. Sign and Publish TX (Issuer side) - let issuer_sk = issuer_keys.private.nostr_prv.to_string(); - let owner_sk = owner_keys.private.nostr_prv.to_string(); - let request = SignPsbtRequest { - psbt: transfer_resp.psbt.clone(), - descriptor: SecretString(issuer_keys.private.rgb_udas_descriptor_xprv.clone()), - }; - let resp = sign_psbt_file(request).await; - assert!(resp.is_ok()); - - // 3. Accept Consig (Issuer Side) - let request = AcceptRequest { - consignment: transfer_resp.consig.clone(), - force: false, - }; - let resp = accept_transfer(&issuer_sk, request).await; - assert!(resp.is_ok()); - assert!(resp?.valid); - // 4. Accept Consig (Owner Side) - let request = AcceptRequest { - consignment: transfer_resp.consig.clone(), - force: false, + let sk = &issuer_keys.private.nostr_prv; + let contract_import = ImportRequest { + import: AssetType::RGB21, + data: UDA_CONTRACT.to_string(), }; - let resp = accept_transfer(&owner_sk, request).await; - assert!(resp.is_ok()); - assert!(resp?.valid); - - // 5. Retrieve Contract (Issuer Side) - let contract_id = &issuer_resp.contract_id; - let resp = get_contract(&issuer_sk, contract_id).await; - assert!(resp.is_ok()); - assert_eq!(0, resp?.balance); - - // 6. Create Watcher (Owner Side) - let watcher_name = "default"; - let create_watch_req = WatcherRequest { - name: watcher_name.to_string(), - xpub: owner_keys.public.watcher_xpub.clone(), - force: true, - }; - create_watcher(&owner_sk, create_watch_req).await?; - - // 7. Retrieve Contract (Owner Side) - let contract_id = &issuer_resp.contract_id; - let resp = get_contract(&owner_sk, contract_id).await; - assert!(resp.is_ok()); - assert_eq!(1, resp?.balance); + let import_resp = import(sk, contract_import).await; + assert!(import_resp.is_ok()); Ok(()) } -// TODO: Review after support multi-token transfer -// async fn _allow_get_collectible_contract_state_by_accept_cosign() -> anyhow::Result<()> { -// // 1. Issue and Generate Trasnfer (Issuer side) -// let collectible = Some(get_collectible_data()); -// let issuer_keys: DecryptedWalletData = save_mnemonic(ISSUER_MNEMONIC, "").await?; -// let owner_keys = save_mnemonic(OWNER_MNEMONIC, "").await?; -// let issuer_resp = issuer_issue_contract("RGB21", 1, false, true, collectible).await?; -// let owner_resp = create_new_invoice(issuer_resp.clone(), None).await?; -// let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer_resp.clone()).await?; -// let transfer_resp = create_new_transfer(issuer_keys.clone(), owner_resp, psbt_resp).await?; - -// // 2. Sign and Publish TX (Issuer side) -// let issuer_sk = issuer_keys.private.nostr_prv.to_string(); -// let owner_sk = owner_keys.private.nostr_prv.to_string(); -// let request = SignPsbtRequest { -// psbt: transfer_resp.clone().psbt, -// mnemonic: ISSUER_MNEMONIC.to_string(), -// seed_password: String::new(), -// iface: issuer_resp.iface, -// }; -// let resp = sign_psbt_file(&issuer_sk, request).await; -// assert!(resp.is_ok()); - -// // 3. Accept Consig (Issuer Side) -// let request = AcceptRequest { -// consignment: transfer_resp.clone().consig, -// force: false, -// }; -// let resp = accept_transfer(&issuer_sk, request).await; -// assert!(resp.is_ok()); -// assert!(resp?.valid); - -// // 4. Accept Consig (Owner Side) -// let request = AcceptRequest { -// consignment: transfer_resp.consig, -// force: false, -// }; -// let resp = accept_transfer(&owner_sk, request).await; -// assert!(resp.is_ok()); -// assert!(resp?.valid); - -// // 5. Retrieve Contract (Issuer Side) -// let contract_id = &issuer_resp.contract_id; -// let resp = get_contract(&issuer_sk, contract_id).await; -// assert!(resp.is_ok()); -// assert_eq!(0, resp?.balance); - -// // 6. Create Watcher (Owner Side) -// let watcher_name = "default"; -// let create_watch_req = WatcherRequest { -// name: watcher_name.to_string(), -// xpub: owner_keys.public.watcher_xpub, -// force: true, -// }; -// create_watcher(&owner_sk, create_watch_req).await?; - -// // 7. Retrieve Contract (Owner Side) -// let contract_id = &issuer_resp.contract_id; -// let resp = get_contract(&owner_sk, contract_id).await; -// assert!(resp.is_ok()); -// assert_eq!(1, resp?.balance); - -// Ok(()) -// } +const FUNGIBLE_CONTRACT: &str = "0100000000030300596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b0100d00799624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100d10718cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010001d007010800d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c03030001000100d00701000100d1070100010001d0070100ffff000001d007d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0001d0070100ffff01d0070100ffff003c000001196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e870501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed707fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a5081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffffffffffffffff0b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0602047574786fe86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c5060570726f6f66f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef083815dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465087a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed91140000000000000000ffffffffffffffff181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb1086015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410100000000000000080000000000000018cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010501560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f9391551541cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904200401deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da8915900501e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e21e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac943750501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed72a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd071cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904220002d2519390702d9a3484b79e289e7bbf2a8cad7fb5d2bc0a5f8471dba6fa3c03c031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a30a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe7680807fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a50000000000000000ffffffffffffffff332de353e616da0cb6394a23d10773fae94ff131f4fe216b2d0001bff1c7b2fb06040776657273696f6ea87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e06696e7075747315dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465076f7574707574738ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca086c6f636b54696d6535da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c339840868f9caa65acd0874d1a06eb2ee2614cdcd537f77615c836cb9a613d93033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a35da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed73c8add893836f8c04c073d1f454d9525cf96a7d7557296fa663ddbaaefa843940334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4050163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc75014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d4050184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515408fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780000000000000000ffff000000000000596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f5be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269050107fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a55ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f00085d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f2203130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f126015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a618622d17baef06602dfe775c980e0b36b6ebae8090d8075f7513bec4b93f64d03020566616c73650004747275650163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a08fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780100000000000000ff0000000000000065eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a06020576616c756597f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b0c7363726970745075626b6579cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea490436632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f0044728ea68a97de7420f62a5969b04b872604bf45d6df38959c7e26e7a72490e4ad033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a7a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed911406040a707265764f7574707574e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50609736967536372697074cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec940873657175656e636501196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e87077769746e657373ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb258057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a50501181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000028000000000000008ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca0865eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a0000000000000000ffffffffffffffff97f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b05015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f99624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10602066e616d696e67de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff58609707265636973696f6e5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f229e14cce6b185cca477ba44634bfa2c5871a97e0c32b7aec1df6a94522a9319c70310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655605012a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdda5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed70004a62e384a135184183b9da6b9796b06e88c75c6803139dd391148ea049ae3d7e10310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66a87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48fbaa0e3fcab9d55d168bb1e26837153afe89f83a27e0498554d3963f6431fd3f4033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7abc2891b1c66ac5f5e61059a32077daa82333a1435bd34608b30b03fc017d9545030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d651deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da891590c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb32544866340360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377fcae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea4904305015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc705013f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec9405015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0000da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b408c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb325448663401000000000000004000000000000000de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff5860603067469636b65728057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5046e616d655014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d40764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0501da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b4e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50606020474786964a38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655604766f757421e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac94375eedec3ebaa08fb010f2f96e17a0e039ad87fe60771a7301f8c5e88995d05676b0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e46ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb25050130a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe768f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffff000000000000f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7afb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc694206030474797065e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0773756274797065c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c0763686172736574c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298cfba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78010001bab043436d5163f8872caa19c3c863c0878364fe504a1c6dcfb0f2d2c62dcfdb0c00035247420300d0d007000000010004d007bab043436d5163f8872caa19c3c863c0878364fe504a1c6dcfb0f2d2c62dcfdb0000019abcb19a89c3e955b796ff9044c1078e81ab142c309d8524c774094a1835838f00055247423230060c6275726e6564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e840001076372656174656401596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b01000c697373756564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e8401010e7265706c61636564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84000104737065630199624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100057465726d730118cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010100050a61737365744f776e657202000001096275726e45706f636801010000096275726e52696768740101000112696e666c6174696f6e416c6c6f77616e6365020100010b7570646174655269676874010100000001467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b04076372656174656400010001000c697373756564537570706c79000100010004737065630001000100057465726d730001000100040a61737365744f776e6572000000ffff096275726e45706f6368000000010012696e666c6174696f6e416c6c6f77616e6365000000ffff0b75706461746552696768740000000100000301030406044275726e0101318ecaa072870bd95230a9515a6aaa14982bac9e3fb15ea2528eb0405227a7a1010c6275726e6564537570706c79000100010001047573656401096275726e526967687401000100010666757475726501096275726e5269676874000001000003010305000549737375650101467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b010c697373756564537570706c7900010001000104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff000401030406010b62656e6566696369617279094f70656e45706f636801000001047573656401096275726e45706f63680100010002096275726e52696768740001000100046e65787401096275726e45706f636800000100000001096275726e52696768740652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265075265706c6163650101318ecaa072870bd95230a9515a6aaa14982bac9e3fb15ea2528eb0405227a7a1010e7265706c61636564537570706c79000100010001047573656401096275726e526967687401000100020b62656e6566696369617279010a61737365744f776e65720000ffff0666757475726501096275726e526967687400000100000401020305010b62656e6566696369617279085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000102010b62656e656669636961727900a1879e8f56bdd6fd8ca323b94f39e060643aa69a39219194d60c4c8a7c7b01c801085472616e7366657200c70931fdf90384c1f4b4f34b2543e80876e35dbf0f15b567ccec8b340b811cc99abcb19a89c3e955b796ff9044c1078e81ab142c309d8524c774094a1835838f0303000763726561746564d0070473706563d107057465726d7301d0070b62656e65666963696172790001d007085472616e7366657200000000c70931fdf90384c1f4b4f34b2543e80876e35dbf0f15b567ccec8b340b811cc98000000303000100040000000000d00701000c00044449424104444942410002d1070100060004004449424101d007010100030177326df3704bdca90c1ad9b33a2e064e88d0cd631bb71ab15619481c2ca92ce7010000002c46352ea481d989080500000000000000073dbed09d95db3df59f8ad1e443bbd0d76f31d804b7eca91f08ab85b1a94ead0000000000000000000000000000"; +const UDA_CONTRACT: &str = "0100000000050300596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b0100340899624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100350818cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010036080b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb00174601003808086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c56840100013408021870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c05030001000100340801000100350801000100360800000100380800000100013408010001000000013408d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0001340801000100013408010001000056000001196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e870501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed707fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a5081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffffffffffffffff086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684060202696477f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f63046e616d65b6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf8205940b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb001746060805696e64657865015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d067469636b6572a1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e046e616d65cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a0764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e40138880770726576696577ae5d4de320882d36a046dd72848e756a08638149d751afac47a0b77d8c2733ac056d656469611b2fd8ca8d5f1671165441ae083116506c4e265a8d7cb9869a409db9701dafaa0b6174746163686d656e7473500a5e82892023b23d60a374fea4fd1f6b3bd66fec3f396fbe8aeac319dc9f8c0872657365727665736e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a3550ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0602047574786fe86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c5060570726f6f66f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed715dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465087a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed91140000000000000000ffffffffffffffff181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb1086015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f41010000000000000008000000000000001870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd59050265015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d19ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7718cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010501560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515419ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7705015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f1a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021b080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000014000000000000001b2fd8ca8d5f1671165441ae083116506c4e265a8d7cb9869a409db9701dafaa040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d652b9fd922298de5f15323ff775a1f79d0d35619fe1298ac9047ead0edf29fb66f1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904200401deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da8915900501e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e21e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac943750501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed72a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd071cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904220002b9fd922298de5f15323ff775a1f79d0d35619fe1298ac9047ead0edf29fb66f0501faa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c025122762d2519390702d9a3484b79e289e7bbf2a8cad7fb5d2bc0a5f8471dba6fa3c03c031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a30a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe7680807fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a50000000000000000ffffffffffffffff332de353e616da0cb6394a23d10773fae94ff131f4fe216b2d0001bff1c7b2fb06040776657273696f6ea87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e06696e7075747315dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465076f7574707574738ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca086c6f636b54696d6535da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c339840868f9caa65acd0874d1a06eb2ee2614cdcd537f77615c836cb9a613d93033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a35da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed73c8add893836f8c04c073d1f454d9525cf96a7d7557296fa663ddbaaefa843940334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4050163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a406e55d3696e06af0b904b93f8a6b2baf00b19b278b2df825db46015395cda8f0501a4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72f45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b060108726573657276657347b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd47b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd090ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0000000000000000ffff000000000000500a5e82892023b23d60a374fea4fd1f6b3bd66fec3f396fbe8aeac319dc9f8c0a0001faa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c02512276000000000000000014000000000000005014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d4050184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515408fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780000000000000000ffff000000000000596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f5be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269050107fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a55ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f00085d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f2203130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f125f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8f05015014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d46015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a618622d17baef06602dfe775c980e0b36b6ebae8090d8075f7513bec4b93f64d03020566616c73650004747275650163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a08fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780100000000000000ff0000000000000065015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed765eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a06020576616c756597f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b0c7363726970745075626b6579cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea490436632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f00446b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de0308106672616374696f6e4f766572666c6f77010e6e6f6e457175616c56616c756573020c696e76616c696450726f6f660314696e73756666696369656e7452657365727665730415697373756545786365656473416c6c6f77616e636506126e6f6e4672616374696f6e616c546f6b656e07126e6f6e456e6772617661626c65546f6b656e0815696e76616c69644174746163686d656e7454797065096e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a355040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d657d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa24728ea68a97de7420f62a5969b04b872604bf45d6df38959c7e26e7a72490e4ad033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a77f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f6300017a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed911406040a707265764f7574707574e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50609736967536372697074cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec940873657175656e636501196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e87077769746e657373ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb257d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa2405010ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd8057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a50501181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000028000000000000008ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca0865eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a0000000000000000ffffffffffffffff97f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b05015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f99624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10602066e616d696e67de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff58609707265636973696f6e5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f229e14cce6b185cca477ba44634bfa2c5871a97e0c32b7aec1df6a94522a9319c70310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46da38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655605012a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdda4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72f06020474797065fb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc69420464617461f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed70004a62e384a135184183b9da6b9796b06e88c75c6803139dd391148ea049ae3d7e10310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66a7ccf154860d368a2b95e87ad394d13d7e6430ac493c7bcdbb95a1c5aea1ccb00602096170706c696564546f65015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d07636f6e74656e74a4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72fa87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48fae5d4de320882d36a046dd72848e756a08638149d751afac47a0b77d8c2733ac040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65406e55d3696e06af0b904b93f8a6b2baf00b19b278b2df825db46015395cda8fb6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf82059405011a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021bbaa0e3fcab9d55d168bb1e26837153afe89f83a27e0498554d3963f6431fd3f4033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7abc2891b1c66ac5f5e61059a32077daa82333a1435bd34608b30b03fc017d9545030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d651deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da891590c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb32544866340360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377fcae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea4904305015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc705013f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec9405015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d655f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8fd83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0000da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b408c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb325448663401000000000000004000000000000000de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff5860603067469636b65728057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5046e616d655014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d40764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0501da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b4e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50606020474786964a38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655604766f757421e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac94375e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46d05018057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5eedec3ebaa08fb010f2f96e17a0e039ad87fe60771a7301f8c5e88995d05676b0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e46ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb25050130a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe768f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffff000000000000f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7afaa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c0251227606020474797065086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684066469676573742a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebddfb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc694206030474797065e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0773756274797065c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c0763686172736574c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298cfba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78010000000001e6b0c7ab8033b92ebfff89bda3e3a4403a7c37454e4d1de2d78f7af8fe83008600055247423231060f6174746163686d656e74547970657301086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c56840001076372656174656401596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b01000a656e67726176696e677301a7ccf154860d368a2b95e87ad394d13d7e6430ac493c7bcdbb95a1c5aea1ccb0000104737065630199624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100057465726d730118cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010006746f6b656e73010b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb0017460001030a61737365744f776e6572051870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900000112696e666c6174696f6e416c6c6f77616e636505140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0100010b7570646174655269676874010100000001467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b050f6174746163686d656e745479706573000000ffff0763726561746564000100010004737065630001000100057465726d73000100010006746f6b656e73000000ffff030a61737365744f776e6572000000ffff12696e666c6174696f6e416c6c6f77616e6365000000ffff0b757064617465526967687400000001000004010304090407456e67726176650100010a656e67726176696e67730001000100010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000401020708010b62656e65666963696172790549737375650101467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b02126e65774174746163686d656e745479706573010f6174746163686d656e7454797065730000ffff096e6577546f6b656e730106746f6b656e730000ffff0104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff00050103040609010b62656e65666963696172790652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff0003010207010b62656e6566696369617279006b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de01085472616e7366657200ca0c967f8bb57d6d85c8a0d0e1ac58816aa9a8d503bb279c50d8e37655f94c73e6b0c7ab8033b92ebfff89bda3e3a4403a7c37454e4d1de2d78f7af8fe8300860403000763726561746564340804737065633508057465726d73360806746f6b656e730134080b62656e656669636961727900013408085472616e7366657200000000ca0c967f8bb57d6d85c8a0d0e1ac58816aa9a8d503bb279c50d8e37655f94c738000000403000100040000000000340801000c0004444942410444494241000235080100060004004449424136080100400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e6700000001340802010003019ee7b29502b09271f6e1f7222fdb5c276d4df6c2b4cd4e33ff960e21e353ae9401000000b4d3d37e2fe0bbb40c000100000001000000000000000000000000000000000000000000"; diff --git a/tests/rgb/integration/states.rs b/tests/rgb/integration/states.rs new file mode 100644 index 00000000..9decde73 --- /dev/null +++ b/tests/rgb/integration/states.rs @@ -0,0 +1,250 @@ +#![cfg(not(target_arch = "wasm32"))] +use bitmask_core::{ + bitcoin::{save_mnemonic, sign_psbt_file}, + rgb::{accept_transfer, create_watcher, get_contract}, + structs::{AcceptRequest, DecryptedWalletData, SecretString, SignPsbtRequest, WatcherRequest}, +}; + +use crate::rgb::integration::utils::{ + create_new_invoice, create_new_psbt, create_new_transfer, get_uda_data, import_new_contract, + issuer_issue_contract, ISSUER_MNEMONIC, OWNER_MNEMONIC, +}; + +#[tokio::test] +async fn allow_import_fungible_contract() -> anyhow::Result<()> { + let issuer_resp = issuer_issue_contract("RGB20", 5, false, true, None).await; + assert!(issuer_resp.is_ok()); + + let import_resp = import_new_contract(issuer_resp?).await; + assert!(import_resp.is_ok()); + Ok(()) +} + +#[tokio::test] +async fn allow_import_uda_contract() -> anyhow::Result<()> { + let single = Some(get_uda_data()); + let issuer_resp = issuer_issue_contract("RGB21", 1, false, true, single).await; + assert!(issuer_resp.is_ok()); + + let import_resp = import_new_contract(issuer_resp?).await; + assert!(import_resp.is_ok()); + Ok(()) +} + +// TODO: Review after support multi-token transfer +// async fn _allow_import_collectible_contract() -> anyhow::Result<()> { +// let collectibles = Some(get_collectible_data()); +// let issuer_resp = issuer_issue_contract("RGB21", 1, false, true, collectibles).await; +// assert!(issuer_resp.is_ok()); + +// let import_resp = import_new_contract(issuer_resp?).await; +// assert!(import_resp.is_ok()); +// Ok(()) +// } + +#[tokio::test] +async fn allow_get_fungible_contract_state_by_accept_cosign() -> anyhow::Result<()> { + // 1. Issue and Generate Trasnfer (Issuer side) + let issuer_keys: DecryptedWalletData = save_mnemonic( + &SecretString(ISSUER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + let owner_keys = save_mnemonic( + &SecretString(OWNER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + let issuer_resp = issuer_issue_contract("RGB20", 5, false, true, None).await?; + let owner_resp = create_new_invoice(issuer_resp.clone(), None).await?; + let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer_resp.clone()).await?; + let transfer_resp = &create_new_transfer(issuer_keys.clone(), owner_resp, psbt_resp).await?; + + // 2. Sign and Publish TX (Issuer side) + let issuer_sk = issuer_keys.private.nostr_prv.to_string(); + let owner_sk = owner_keys.private.nostr_prv.to_string(); + let request = SignPsbtRequest { + psbt: transfer_resp.psbt.clone(), + descriptor: SecretString(issuer_keys.private.rgb_assets_descriptor_xprv.clone()), + }; + let resp = sign_psbt_file(request).await; + assert!(resp.is_ok()); + + // 3. Accept Consig (Issuer Side) + let request = AcceptRequest { + consignment: transfer_resp.clone().consig, + force: true, + }; + let resp = accept_transfer(&issuer_sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + + // 4. Accept Consig (Owner Side) + let request = AcceptRequest { + consignment: transfer_resp.consig.clone(), + force: false, + }; + let resp = accept_transfer(&owner_sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + + // 5. Retrieve Contract (Issuer Side) + let contract_id = &issuer_resp.contract_id; + let resp = get_contract(&issuer_sk, contract_id).await; + assert!(resp.is_ok()); + assert_eq!(4, resp?.balance); + + // 6. Create Watcher (Owner Side) + let watcher_name = "default"; + let create_watch_req = WatcherRequest { + name: watcher_name.to_string(), + xpub: owner_keys.public.watcher_xpub.clone(), + force: true, + }; + create_watcher(&owner_sk, create_watch_req).await?; + + // 7. Retrieve Contract (Owner Side) + let contract_id = &issuer_resp.contract_id; + let resp = get_contract(&owner_sk, contract_id).await; + assert!(resp.is_ok()); + assert_eq!(1, resp?.balance); + + Ok(()) +} + +#[tokio::test] +async fn allow_get_uda_contract_state_by_accept_cosign() -> anyhow::Result<()> { + // 1. Issue and Generate Trasnfer (Issuer side) + let single = Some(get_uda_data()); + let issuer_keys: DecryptedWalletData = save_mnemonic( + &SecretString(ISSUER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + let owner_keys = save_mnemonic( + &SecretString(OWNER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + + let issuer_resp = issuer_issue_contract("RGB21", 1, false, true, single).await?; + let owner_resp = create_new_invoice(issuer_resp.clone(), None).await?; + let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer_resp.clone()).await?; + let transfer_resp = &create_new_transfer(issuer_keys.clone(), owner_resp, psbt_resp).await?; + + // 2. Sign and Publish TX (Issuer side) + let issuer_sk = issuer_keys.private.nostr_prv.to_string(); + let owner_sk = owner_keys.private.nostr_prv.to_string(); + let request = SignPsbtRequest { + psbt: transfer_resp.psbt.clone(), + descriptor: SecretString(issuer_keys.private.rgb_udas_descriptor_xprv.clone()), + }; + let resp = sign_psbt_file(request).await; + assert!(resp.is_ok()); + + // 3. Accept Consig (Issuer Side) + let request = AcceptRequest { + consignment: transfer_resp.consig.clone(), + force: false, + }; + let resp = accept_transfer(&issuer_sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + + // 4. Accept Consig (Owner Side) + let request = AcceptRequest { + consignment: transfer_resp.consig.clone(), + force: false, + }; + let resp = accept_transfer(&owner_sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + + // 5. Retrieve Contract (Issuer Side) + let contract_id = &issuer_resp.contract_id; + let resp = get_contract(&issuer_sk, contract_id).await; + assert!(resp.is_ok()); + assert_eq!(0, resp?.balance); + + // 6. Create Watcher (Owner Side) + let watcher_name = "default"; + let create_watch_req = WatcherRequest { + name: watcher_name.to_string(), + xpub: owner_keys.public.watcher_xpub.clone(), + force: true, + }; + create_watcher(&owner_sk, create_watch_req).await?; + + // 7. Retrieve Contract (Owner Side) + let contract_id = &issuer_resp.contract_id; + let resp = get_contract(&owner_sk, contract_id).await; + assert!(resp.is_ok()); + assert_eq!(1, resp?.balance); + + Ok(()) +} + +// TODO: Review after support multi-token transfer +// async fn _allow_get_collectible_contract_state_by_accept_cosign() -> anyhow::Result<()> { +// // 1. Issue and Generate Trasnfer (Issuer side) +// let collectible = Some(get_collectible_data()); +// let issuer_keys: DecryptedWalletData = save_mnemonic(ISSUER_MNEMONIC, "").await?; +// let owner_keys = save_mnemonic(OWNER_MNEMONIC, "").await?; +// let issuer_resp = issuer_issue_contract("RGB21", 1, false, true, collectible).await?; +// let owner_resp = create_new_invoice(issuer_resp.clone(), None).await?; +// let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer_resp.clone()).await?; +// let transfer_resp = create_new_transfer(issuer_keys.clone(), owner_resp, psbt_resp).await?; + +// // 2. Sign and Publish TX (Issuer side) +// let issuer_sk = issuer_keys.private.nostr_prv.to_string(); +// let owner_sk = owner_keys.private.nostr_prv.to_string(); +// let request = SignPsbtRequest { +// psbt: transfer_resp.clone().psbt, +// mnemonic: ISSUER_MNEMONIC.to_string(), +// seed_password: String::new(), +// iface: issuer_resp.iface, +// }; +// let resp = sign_psbt_file(&issuer_sk, request).await; +// assert!(resp.is_ok()); + +// // 3. Accept Consig (Issuer Side) +// let request = AcceptRequest { +// consignment: transfer_resp.clone().consig, +// force: false, +// }; +// let resp = accept_transfer(&issuer_sk, request).await; +// assert!(resp.is_ok()); +// assert!(resp?.valid); + +// // 4. Accept Consig (Owner Side) +// let request = AcceptRequest { +// consignment: transfer_resp.consig, +// force: false, +// }; +// let resp = accept_transfer(&owner_sk, request).await; +// assert!(resp.is_ok()); +// assert!(resp?.valid); + +// // 5. Retrieve Contract (Issuer Side) +// let contract_id = &issuer_resp.contract_id; +// let resp = get_contract(&issuer_sk, contract_id).await; +// assert!(resp.is_ok()); +// assert_eq!(0, resp?.balance); + +// // 6. Create Watcher (Owner Side) +// let watcher_name = "default"; +// let create_watch_req = WatcherRequest { +// name: watcher_name.to_string(), +// xpub: owner_keys.public.watcher_xpub, +// force: true, +// }; +// create_watcher(&owner_sk, create_watch_req).await?; + +// // 7. Retrieve Contract (Owner Side) +// let contract_id = &issuer_resp.contract_id; +// let resp = get_contract(&owner_sk, contract_id).await; +// assert!(resp.is_ok()); +// assert_eq!(1, resp?.balance); + +// Ok(()) +// } From ce35c190232d43d015dab010f332508391704241 Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Mon, 26 Jun 2023 21:57:10 -0300 Subject: [PATCH 02/27] feat: conseq transfers --- .github/workflows/rust.yaml | 8 +- src/rgb.rs | 72 ++-- src/rgb/contract.rs | 83 +++-- src/rgb/prefetch.rs | 20 +- src/rgb/psbt.rs | 154 ++++++-- src/rgb/transfer.rs | 9 +- src/rgb/wallet.rs | 174 +++++++-- src/structs.rs | 6 +- tests/rgb.rs | 3 +- tests/rgb/integration/fungibles.rs | 31 +- tests/rgb/integration/states.rs | 57 ++- tests/rgb/integration/stress.rs | 24 +- tests/rgb/integration/transfers.rs | 556 +++++++++++++++++++++++++++++ tests/rgb/integration/udas.rs | 30 +- tests/rgb/integration/utils.rs | 75 ++-- tests/rgb/unit/psbt.rs | 1 + tests/rgb/web/imports.rs | 4 +- 17 files changed, 1096 insertions(+), 211 deletions(-) create mode 100644 tests/rgb/integration/transfers.rs diff --git a/.github/workflows/rust.yaml b/.github/workflows/rust.yaml index 84d1c8cd..7fff81d0 100644 --- a/.github/workflows/rust.yaml +++ b/.github/workflows/rust.yaml @@ -40,7 +40,7 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Lint - run: cargo clippy --all-features --lib --message-format=json -- -D warnings | cargo-action-fmt + run: cargo clippy --locked --all-features --lib --message-format=json -- -D warnings | cargo-action-fmt lint-wasm: runs-on: ubuntu-latest @@ -62,7 +62,7 @@ jobs: run: rustup target add wasm32-unknown-unknown - name: Lint (wasm32) - run: cargo clippy --target wasm32-unknown-unknown --lib --message-format=json -- -D warnings | cargo-action-fmt + run: cargo clippy --locked --target wasm32-unknown-unknown --lib --message-format=json -- -D warnings | cargo-action-fmt test: runs-on: ubuntu-latest @@ -97,7 +97,7 @@ jobs: RUST_BACKTRACE: 1 - name: RGB Tests - run: cargo test --features server --test rgb -- rgb --nocapture --test-threads 1 + run: cargo test --locked --features server --test rgb -- rgb --nocapture --test-threads 1 env: TEST_WALLET_SEED: ${{ secrets.TEST_WALLET_SEED }} RUST_BACKTRACE: 1 @@ -142,7 +142,7 @@ jobs: RUST_BACKTRACE: 1 - name: Run bitmaskd node - run: cargo run --features server & sleep 1 + run: cargo run --locked --features server & sleep 1 - name: Test WASM run: wasm-pack test --headless --chrome diff --git a/src/rgb.rs b/src/rgb.rs index 55ebf805..8cfbba37 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -97,7 +97,7 @@ pub async fn issue_contract(sk: &str, request: IssueRequest) -> Result { let mut fetch_wallet = wallet.to_owned(); for contract_type in [AssetType::RGB20, AssetType::RGB21] { - prefetch_resolver_utxos(contract_type as u32, &mut resolver, &mut fetch_wallet) + prefetch_resolver_utxos(contract_type as u32, &mut fetch_wallet, &mut resolver) .await; } @@ -192,10 +192,11 @@ pub async fn create_psbt(sk: &str, request: PsbtRequest) -> Result change_index, bitcoin_changes, fee, - input_tweak, + tapret, } = request; - let stock: rgbstd::persistence::Stock = retrieve_stock(sk, ASSETS_STOCK).await?; + let stock = retrieve_stock(sk, ASSETS_STOCK).await?; + let rgb_account = retrieve_wallets(sk, ASSETS_WALLETS).await?; // Prefetch let mut resolver = ExplorerResolver { @@ -207,18 +208,17 @@ pub async fn create_psbt(sk: &str, request: PsbtRequest) -> Result // Retrieve transaction fee let fee = match fee { Some(fee) => fee, - _ => { - estimate_fee_tx( - &descriptor_pub, - &asset_utxo, - &asset_utxo_terminal, - change_index, - bitcoin_changes.clone(), - ) - .await - } + _ => estimate_fee_tx( + &descriptor_pub, + &asset_utxo, + &asset_utxo_terminal, + change_index, + bitcoin_changes.clone(), + &mut resolver, + ), }; + let wallet = rgb_account.wallets.get("default"); let (psbt_file, change_terminal) = create_rgb_psbt( descriptor_pub.0.to_string(), asset_utxo, @@ -226,7 +226,8 @@ pub async fn create_psbt(sk: &str, request: PsbtRequest) -> Result change_index, bitcoin_changes, fee, - input_tweak, + wallet.cloned(), + tapret, &resolver, )?; @@ -284,7 +285,6 @@ pub async fn transfer_asset(sk: &str, request: RgbTransferRequest) -> Result Result { let AcceptRequest { consignment, force } = request; - let mut stock = retrieve_stock(sk, ASSETS_STOCK).await?; // Prefetch @@ -326,7 +326,7 @@ pub async fn get_contract(sk: &str, contract_id: &str) -> Result { let mut fetch_wallet = wallet.to_owned(); for contract_type in [AssetType::RGB20, AssetType::RGB21] { - prefetch_resolver_utxos(contract_type as u32, &mut resolver, &mut fetch_wallet) + prefetch_resolver_utxos(contract_type as u32, &mut fetch_wallet, &mut resolver) .await; } @@ -363,7 +363,7 @@ pub async fn list_contracts(sk: &str) -> Result { 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 resolver, &mut fetch_wallet) + prefetch_resolver_utxos(contract_type as u32, &mut fetch_wallet, &mut resolver) .await; } Some(fetch_wallet) @@ -445,7 +445,7 @@ pub async fn import(sk: &str, request: ImportRequest) -> Result { let mut fetch_wallet = wallet.to_owned(); - prefetch_resolver_utxos(import as u32, &mut resolver, &mut fetch_wallet).await; + prefetch_resolver_utxos(import as u32, &mut fetch_wallet, &mut resolver).await; Some(fetch_wallet) } _ => None, @@ -523,7 +523,8 @@ pub async fn watcher_details(sk: &str, name: &str) -> Result Result Result = [0, 1, 9, 20, 21].to_vec(); let mut wallet = wallet.to_owned(); - prefetch_resolver_waddress(address, &mut wallet, &mut resolver).await; - resp.utxos = register_address(address, asset_indexes, &mut wallet, &mut resolver)? - .into_iter() - .map(|utxo| utxo.outpoint.to_string()) - .collect(); + prefetch_resolver_waddress(address, &mut wallet, &mut resolver, Some(20)).await; + resp.utxos = + register_address(address, asset_indexes, &mut wallet, &mut resolver, Some(20))? + .into_iter() + .map(|utxo| utxo.outpoint.to_string()) + .collect(); }; Ok(resp) @@ -582,11 +583,18 @@ pub async fn watcher_utxo(sk: &str, name: &str, utxo: &str) -> Result = [0, 1, 9, 20, 21].to_vec(); let mut wallet = wallet.to_owned(); - prefetch_resolver_wutxo(utxo, network, &mut wallet, &mut resolver).await; - resp.utxos = register_utxo(utxo, network, asset_indexes, &mut wallet, &mut resolver)? - .into_iter() - .map(|utxo| utxo.outpoint.to_string()) - .collect(); + prefetch_resolver_wutxo(utxo, network, &mut wallet, &mut resolver, Some(20)).await; + resp.utxos = register_utxo( + utxo, + network, + asset_indexes, + &mut wallet, + &mut resolver, + Some(20), + )? + .into_iter() + .map(|utxo| utxo.outpoint.to_string()) + .collect(); }; Ok(resp) @@ -645,8 +653,8 @@ pub async fn watcher_next_utxo(sk: &str, name: &str, iface: &str) -> Result( contract_id: ContractId, stock: &mut Stock, - resolver: &mut impl Resolver, + resolver: &mut T, wallet: &mut Option, -) -> Result { +) -> Result +where + T: ResolveSpent + Resolver, +{ let contract_bindle = stock .export_contract(contract_id) .expect("contract not found"); @@ -66,7 +70,6 @@ pub fn extract_contract_by_id( let mut name = String::new(); let mut precision = 0; let mut description = String::new(); - let mut supply = 0; let ty: FieldName = FieldName::from("spec"); let nominal = match contract_iface.global(ty) { @@ -89,12 +92,10 @@ pub fn extract_contract_by_id( name = val[2..val.len() - 2].to_string(); }; } - if naming.contains_key(&FieldName::from("precision")) { - if let Some(val) = naming.get(&FieldName::from("precision")) { - let val = val.to_string(); - precision = val.parse()?; - }; - } + } + if let Some(StrictVal::Enum(en)) = fields.get(&FieldName::from("precision")) { + let val = en.unwrap_ord(); + precision = val as u64; } }; } @@ -112,42 +113,25 @@ pub fn extract_contract_by_id( }; } - let empty = EmptyFilter {}; - for owned in &contract_iface.iface.assignments { - if let Ok(allocations) = contract_iface.fungible(owned.name.clone(), Some(&empty)) { - for allocation in allocations { - supply = allocation.value; - } - } - - if let Ok(allocations) = contract_iface.data(owned.name.clone()) { - for _ in allocations { - supply += 1; - } - } - } - let mut balance = 0; - let mut allocations = vec![]; - - // TODO: workaround let iface_index = match iface.name.as_str() { "RGB20" => 20, "RGB21" => 21, _ => 9, }; + let mut balance = 0; + let mut allocations = vec![]; + let contract_id = ContractId::from_str(&contract_id)?; if let Some(wallet) = wallet { - let watcher = list_allocations(wallet, stock, iface_index, resolver) + let watcher = allocations_by_contract(contract_id, iface_index, wallet, stock, resolver) .expect("invalid allocation states"); - if let Some(mut watcher_detail) = watcher.into_iter().find(|w| w.contract_id == contract_id) - { - allocations.append(&mut watcher_detail.allocations); - } + allocations = watcher.allocations; balance = allocations .clone() .into_iter() .filter(|a| a.is_mine) + .filter(|a| !a.is_spent) .map(|a| match a.value { AllocationValue::Value(value) => value.to_owned(), AllocationValue::UDA(_) => 1, @@ -156,10 +140,31 @@ pub fn extract_contract_by_id( } // Genesis - let genesis = stock - .export_contract(ContractId::from_str(&contract_id)?) + let contract_genesis = stock + .export_contract(contract_id) .expect("contract have genesis"); + let mut supply = 0; + 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") + { + 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() + { + supply += 1; + } + } + + let genesis = contract_genesis.genesis.clone(); let genesis_strict = genesis .to_strict_serialized::<0xFFFFFF>() .expect("invalid genesis data") @@ -178,7 +183,7 @@ pub fn extract_contract_by_id( let genesis_formats = GenesisFormats { legacy: genesis_legacy, strict: genesis_strict, - armored: genesis.to_string(), + armored: "".to_string(), }; // Only RGB21/UDA @@ -297,7 +302,7 @@ pub fn extract_contract_by_id( } let resp = ContractResponse { - contract_id, + contract_id: contract_id.to_string(), iimpl_id, iface: iface.name.to_string(), ticker, diff --git a/src/rgb/prefetch.rs b/src/rgb/prefetch.rs index 6e91e620..5474add2 100644 --- a/src/rgb/prefetch.rs +++ b/src/rgb/prefetch.rs @@ -31,7 +31,7 @@ pub async fn prefetch_resolver_psbt(asset_utxo: &str, explorer: &mut ExplorerRes #[cfg(not(target_arch = "wasm32"))] pub async fn prefetch_resolver_utxo_status( iface_index: u32, - wallet: RgbWallet, + wallet: &mut RgbWallet, explorer: &mut ExplorerResolver, ) { } @@ -39,8 +39,8 @@ pub async fn prefetch_resolver_utxo_status( #[cfg(not(target_arch = "wasm32"))] pub async fn prefetch_resolver_utxos( iface_index: u32, - explorer: &mut ExplorerResolver, wallet: &mut RgbWallet, + explorer: &mut ExplorerResolver, ) { } @@ -52,6 +52,7 @@ pub async fn prefetch_resolver_waddress( address: &str, wallet: &mut RgbWallet, explorer: &mut ExplorerResolver, + limit: Option, ) { } @@ -61,6 +62,7 @@ pub async fn prefetch_resolver_wutxo( network: AddressNetwork, wallet: &mut RgbWallet, explorer: &mut ExplorerResolver, + limit: Option, ) { } @@ -142,13 +144,14 @@ pub async fn prefetch_resolver_psbt(asset_utxo: &str, explorer: &mut ExplorerRes #[cfg(target_arch = "wasm32")] pub async fn prefetch_resolver_utxo_status( iface_index: u32, - wallet: RgbWallet, + wallet: &mut RgbWallet, explorer: &mut ExplorerResolver, ) { let esplora_client: EsploraBlockchain = EsploraBlockchain::new(&explorer.explorer_url, 100).with_concurrency(6); let utxos: Vec = wallet .utxos + .clone() .into_iter() .filter(|utxo| { utxo.derivation.terminal.app == iface_index && utxo.derivation.tweak.is_none() @@ -176,8 +179,8 @@ pub async fn prefetch_resolver_utxo_status( #[cfg(target_arch = "wasm32")] pub async fn prefetch_resolver_utxos( iface_index: u32, - explorer: &mut ExplorerResolver, wallet: &mut RgbWallet, + explorer: &mut ExplorerResolver, ) { let esplora_client: EsploraBlockchain = EsploraBlockchain::new(&explorer.explorer_url, 100).with_concurrency(6); @@ -259,11 +262,15 @@ pub async fn prefetch_resolver_waddress( address: &str, wallet: &mut RgbWallet, explorer: &mut ExplorerResolver, + limit: Option, ) { let esplora_client: EsploraBlockchain = EsploraBlockchain::new(&explorer.explorer_url, 100).with_concurrency(6); - let step = 100; + let mut step = 100; + if let Some(limit) = limit { + step = limit; + } let index = 0; let sc = AddressCompat::from_str(address).expect("invalid address"); @@ -334,6 +341,7 @@ pub async fn prefetch_resolver_wutxo( network: AddressNetwork, wallet: &mut RgbWallet, explorer: &mut ExplorerResolver, + limit: Option, ) { let esplora_client: EsploraBlockchain = EsploraBlockchain::new(&explorer.explorer_url, 100).with_concurrency(6); @@ -349,7 +357,7 @@ pub async fn prefetch_resolver_wutxo( let sc = Script::from_str(&vout.script_pubkey.to_hex()).expect("invalid script"); let pub_script = PubkeyScript::from(sc); if let Some(address) = AddressCompat::from_script(&pub_script, network) { - prefetch_resolver_waddress(&address.to_string(), wallet, explorer).await; + prefetch_resolver_waddress(&address.to_string(), wallet, explorer, limit).await; } } } diff --git a/src/rgb/psbt.rs b/src/rgb/psbt.rs index a90efa48..c62e017c 100644 --- a/src/rgb/psbt.rs +++ b/src/rgb/psbt.rs @@ -4,18 +4,26 @@ use amplify::hex::ToHex; use bdk::wallet::coin_selection::{decide_change, Excess}; use bdk::FeeRate; use bitcoin::secp256k1::SECP256K1; +use bitcoin::util::bip32::Fingerprint; use bitcoin::{EcdsaSighashType, OutPoint, Script, XOnlyPublicKey}; +// TODO: Incompletible versions between RGB and Descriptor Wallet +use bitcoin_30::secp256k1::SECP256K1 as SECP256K1_30; +use bitcoin_30::taproot::TaprootBuilder; +use bitcoin_30::ScriptBuf; use bitcoin_blockchain::locks::SeqNo; use bitcoin_scripts::PubkeyScript; use bp::dbc::tapret::TapretCommitment; +use bp::TapScript; use commit_verify::mpc::Commitment; +use commit_verify::CommitVerify; + use miniscript_crate::Descriptor; use psbt::{ProprietaryKey, ProprietaryKeyType}; use rgb::psbt::{ DbcPsbtError, TapretKeyError, PSBT_OUT_TAPRET_COMMITMENT, PSBT_OUT_TAPRET_HOST, PSBT_TAPRET_PREFIX, }; -use rgb::{RgbDescr, RgbWallet, TerminalPath}; +use rgb::{Resolver, RgbDescr, RgbWallet, TerminalPath}; use wallet::descriptors::derive::DeriveDescriptor; use wallet::hd::DerivationSubpath; use wallet::psbt::Psbt; @@ -26,7 +34,6 @@ use wallet::{ psbt::{ProprietaryKeyDescriptor, ProprietaryKeyError, ProprietaryKeyLocation}, }; -use crate::bitcoin::{get_wallet, sync_wallet}; use crate::rgb::{constants::RGB_PSBT_TAPRET, structs::AddressAmount}; use crate::structs::SecretString; @@ -38,11 +45,12 @@ pub fn create_psbt( change_index: Option, bitcoin_changes: Vec, fee: u64, - _tap_tweak: Option, + wallet: Option, + tapret: Option, tx_resolver: &impl ResolveTx, ) -> Result<(Psbt, String), ProprietaryKeyError> { let outpoint: OutPoint = asset_utxo.parse().expect("invalid outpoint parse"); - let input = InputDescriptor { + let mut input = InputDescriptor { outpoint, terminal: asset_utxo_terminal .parse() @@ -80,6 +88,7 @@ pub fn create_psbt( value: None, }]; + // Change Terminal Derivation let mut change_derivation = vec![input.terminal[0]]; let change_index = match change_index { Some(index) => { @@ -88,9 +97,22 @@ pub fn create_psbt( _ => UnhardenedIndex::default(), }; change_derivation.insert(1, change_index); - let change_terminal = format!("/{contract_index}/{change_index}"); + // Verify TapTweak (User Input) + if let Some(tapret) = tapret { + input.tweak = Some(( + Fingerprint::default(), + tapret.parse().expect("invalid hash"), + )) + } + // Verify TapTweak (Watcher inspect) + else if let Some(tweak) = + complete_input_desc(descriptor.clone(), input.clone(), wallet, tx_resolver).expect("") + { + input.tweak = Some((Fingerprint::default(), tweak.parse().expect("invalid hash"))) + } + let inputs = vec![input]; let mut psbt = Psbt::construct( descriptor, @@ -137,6 +159,89 @@ pub fn create_psbt( Ok((psbt, change_terminal)) } +fn complete_input_desc( + descriptor: Descriptor, + input: InputDescriptor, + wallet: Option, + tx_resolver: &impl ResolveTx, +) -> anyhow::Result> { + let txid = input.outpoint.txid; + let tx = tx_resolver.resolve_tx(txid).expect("tx not found"); + let prev_output = tx.output.get(input.outpoint.vout as usize).unwrap(); + + let mut scripts = bmap![]; + if let Descriptor::Tr(_) = descriptor { + let output_descriptor = DeriveDescriptor::::derive_descriptor( + &descriptor, + SECP256K1, + &input.terminal, + ) + .expect("invalid descriptor"); + + scripts.insert(output_descriptor.script_pubkey(), None); + + if let Some(walet) = wallet { + let RgbDescr::Tapret(tapret_desc) = walet.descr; + let contract_index = u32::from_str( + &input + .terminal + .first() + .expect("first derivation index") + .to_string(), + ) + .expect("invalid parse"); + let change_index = u32::from_str( + &input + .terminal + .last() + .expect("first derivation index") + .to_string(), + ) + .expect("invalid parse"); + + let terminal = TerminalPath { + app: contract_index, + index: change_index, + }; + + if let Some(taprets) = tapret_desc.taprets.get(&terminal) { + taprets.iter().for_each(|tweak| { + if let Descriptor::::Tr(tr_desc) = &output_descriptor { + let xonly = tr_desc.internal_key(); + + let tap_tweak = ScriptBuf::from_bytes(TapScript::commit(tweak).to_vec()); + let tap_builder = TaprootBuilder::with_capacity(1) + .add_leaf(0, tap_tweak) + .expect("complete tree"); + + // TODO: Incompletible versions between RGB and Descriptor Wallet + let xonly_30 = + bitcoin_30::secp256k1::XOnlyPublicKey::from_str(&xonly.to_hex()) + .expect(""); + + let spent_info = tap_builder + .finalize(SECP256K1_30, xonly_30) + .expect("complete tree"); + + let merkle_root = spent_info.merkle_root().expect("script tree present"); + let tap_script = + ScriptBuf::new_v1_p2tr(SECP256K1_30, xonly_30, Some(merkle_root)); + + let spk = Script::from_str(&tap_script.as_script().to_hex()).expect("msg"); + scripts.insert(spk, Some(merkle_root.to_hex())); + } + }); + } + } + }; + + let result = scripts + .into_iter() + .find(|(sc, _)| sc.clone() == prev_output.script_pubkey) + .expect("derived scriptPubkey does not match transaction scriptPubkey"); + Ok(result.1) +} + pub fn extract_commit(mut psbt: Psbt) -> Result, DbcPsbtError> { let (_, output) = psbt .outputs @@ -183,30 +288,30 @@ pub fn save_commit(terminal: &str, commit: Vec, wallet: &mut RgbWallet) { } // TODO: [Experimental] Review with Diba Team -pub async fn estimate_fee_tx( +pub fn estimate_fee_tx( descriptor_pub: &SecretString, asset_utxo: &str, asset_utxo_terminal: &str, - change_index: Option, + asset_change_index: Option, bitcoin_changes: Vec, -) -> u64 { + resolver: &mut T, +) -> u64 +where + T: ResolveTx + Resolver, +{ let outpoint = OutPoint::from_str(asset_utxo).expect("invalid outpoint"); - let wallet = get_wallet(descriptor_pub, None) - .await - .expect("cannot retrieve wallet"); - - sync_wallet(&wallet).await.expect(""); - - let local = wallet.lock().await.get_utxo(outpoint); - let local = local.expect("utxo not found").unwrap(); - - let change_index = match change_index { - Some(index) => { - UnhardenedIndex::from_str(&index.to_string()).expect("invalid change_index parse") - } + let asset_change_index = match asset_change_index { + Some(index) => index.into(), _ => UnhardenedIndex::default(), }; + let mut vout_value = 0; + if let Ok(tx) = resolver.resolve_tx(outpoint.txid) { + if let Some(vout) = tx.output.to_vec().get(outpoint.vout as usize) { + vout_value = vout.value; + } + } + // Other Recipient let mut total_spent = 0; for bitcoin_change in bitcoin_changes { @@ -216,9 +321,10 @@ pub async fn estimate_fee_tx( } // Main Recipient - total_spent = local.txout.value - total_spent; - let target_script = get_recipient_script(descriptor_pub, asset_utxo_terminal, change_index) - .expect("invalid derivation"); + total_spent = vout_value - total_spent; + let target_script = + get_recipient_script(descriptor_pub, asset_utxo_terminal, asset_change_index) + .expect("invalid derivation"); // TODO: Provide way to get fee rate estimate let fee_rate = FeeRate::from_sat_per_vb(5.0); diff --git a/src/rgb/transfer.rs b/src/rgb/transfer.rs index 025ee71d..7c1d0a2a 100644 --- a/src/rgb/transfer.rs +++ b/src/rgb/transfer.rs @@ -150,9 +150,12 @@ where let confined_transfer = Transfer::from_strict_serialized::<{ usize::MAX }>(confined); let transfer = confined_transfer.expect("invalid strict transfer format data"); - let transfer_status = transfer - .validate(resolver) - .expect("transfer cannot be validated"); + let transfer_status = match transfer.validate(resolver) { + Ok(status) => status, + Err(status) => status, + }; + // .validate(resolver) + // .expect("transfer cannot be validated"); let bindle = Bindle::new(transfer_status.clone()); match stock.accept_transfer(transfer_status, resolver, force) { diff --git a/src/rgb/wallet.rs b/src/rgb/wallet.rs index 16d63279..100d743d 100644 --- a/src/rgb/wallet.rs +++ b/src/rgb/wallet.rs @@ -9,6 +9,7 @@ use bp::dbc::tapret::TapretCommitment; use commit_verify::mpc::Commitment; use rgb::{DeriveInfo, Resolver, RgbDescr, RgbWallet, SpkDescriptor, Tapret, TerminalPath, Utxo}; use rgbstd::{ + contract::ContractId, persistence::{Inventory, Stash, Stock}, validation::ResolveTx, }; @@ -154,14 +155,7 @@ pub fn sync_wallet(iface_index: u32, wallet: &mut RgbWallet, resolver: &mut impl let index = 0; let scripts = wallet.descr.derive(iface_index, index..step); - let new_scripts = scripts - .into_iter() - .map(|(d, sc)| { - // Reconstruct Taptree - - (d, sc) - }) - .collect(); + let new_scripts = scripts.into_iter().map(|(d, sc)| (d, sc)).collect(); let mut new_utxos = resolver .resolve_utxo(new_scripts) @@ -176,12 +170,16 @@ pub fn register_address( asset_indexes: Vec, wallet: &mut RgbWallet, resolver: &mut T, + limit: Option, ) -> Result, anyhow::Error> where T: ResolveTx + Resolver, { - let step = 100; let index = 0; + let mut step = 100; + if let Some(limit) = limit { + step = limit; + } let sc = AddressCompat::from_str(address).expect("invalid address"); let script = ScriptBuf::from_hex(&sc.script_pubkey().to_hex()).expect("invalid script"); @@ -213,6 +211,7 @@ pub fn register_utxo( asset_indexes: Vec, wallet: &mut RgbWallet, resolver: &mut T, + limit: Option, ) -> Result, anyhow::Error> where T: ResolveTx + Resolver, @@ -226,21 +225,47 @@ where let sc = Script::from_str(&vout.script_pubkey.to_hex()).expect("invalid script"); let pub_script = PubkeyScript::from(sc); if let Some(address) = AddressCompat::from_script(&pub_script, network) { - utxos = register_address(&address.to_string(), asset_indexes, wallet, resolver) - .expect("invalid utxos"); + utxos = + register_address(&address.to_string(), asset_indexes, wallet, resolver, limit) + .expect("invalid utxos"); } } } - Ok(utxos) } -pub fn list_allocations( +pub fn save_commitment( + iface_index: u32, + path: TerminalPath, + commit: String, + wallet: &mut RgbWallet, +) { + let mpc = Commitment::from_str(&commit).expect("invalid commitment"); + let tap_commit = TapretCommitment::with(mpc, 0); + + let mut utxo = wallet + .utxos + .clone() + .into_iter() + .find(|utxo| { + utxo.derivation.terminal.app == iface_index && utxo.derivation.terminal == path + }) + .expect("invalid UTXO reference"); + + wallet.utxos.remove(&utxo); + utxo.derivation.tweak = Some(tap_commit); + wallet.utxos.insert(utxo); +} + +pub fn list_allocations( wallet: &mut RgbWallet, stock: &mut Stock, iface_index: u32, - resolver: &mut impl Resolver, -) -> Result, anyhow::Error> { + resolver: &mut T, +) -> Result, anyhow::Error> +where + T: ResolveSpent + Resolver, +{ let iface_name = match iface_index { 20 => "RGB20", 21 => "RGB21", @@ -257,6 +282,12 @@ pub fn list_allocations( for owned in &contract.iface.assignments { if let Ok(allocations) = contract.fungible(owned.name.clone(), Some(&empty)) { for allocation in allocations { + let txid = bitcoin::Txid::from_str(&allocation.owner.txid.to_hex()) + .expect("invalid txid"); + let is_spent = resolver + .resolve_spent_status(txid, allocation.owner.vout.into_u32().into()) + .expect("cannot find utxo"); + if let Some(utxo) = wallet.utxo(allocation.owner) { owners.push(AllocationDetail { utxo: utxo.outpoint.to_string(), @@ -266,6 +297,7 @@ pub fn list_allocations( utxo.derivation.terminal.app, utxo.derivation.terminal.index ), is_mine: true, + is_spent, }); } else { owners.push(AllocationDetail { @@ -273,6 +305,7 @@ pub fn list_allocations( value: AllocationValue::Value(allocation.value), derivation: default!(), is_mine: false, + is_spent, }); } } @@ -280,6 +313,12 @@ pub fn list_allocations( if let Ok(allocations) = contract.data(owned.name.clone()) { for allocation in allocations { + let txid = bitcoin::Txid::from_str(&allocation.owner.txid.to_hex()) + .expect("invalid txid"); + let is_spent = resolver + .resolve_spent_status(txid, allocation.owner.vout.into_u32().into()) + .expect("cannot find utxo"); + if let Some(utxo) = wallet.utxo(allocation.owner) { owners.push(AllocationDetail { utxo: utxo.outpoint.to_string(), @@ -289,6 +328,7 @@ pub fn list_allocations( utxo.derivation.terminal.app, utxo.derivation.terminal.index ), is_mine: true, + is_spent, }); } else { owners.push(AllocationDetail { @@ -296,6 +336,7 @@ pub fn list_allocations( value: AllocationValue::UDA(UDAPosition::with(allocation.value)), derivation: default!(), is_mine: false, + is_spent, }); } } @@ -311,25 +352,94 @@ pub fn list_allocations( Ok(details) } -pub fn save_commitment( +pub fn allocations_by_contract( + contract_id: ContractId, iface_index: u32, - path: TerminalPath, - commit: String, wallet: &mut RgbWallet, -) { - let mpc = Commitment::from_str(&commit).expect("invalid commitment"); - let tap_commit = TapretCommitment::with(mpc, 0); + stock: &mut Stock, + resolver: &mut T, +) -> Result +where + T: ResolveSpent + Resolver, +{ + let empty = EmptyFilter {}; + let iface_name = match iface_index { + 20 => "RGB20", + 21 => "RGB21", + _ => "Contract", + }; + let iface = stock.iface_by_name(&tn!(iface_name))?; + + let mut owners = vec![]; + 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)) { + for allocation in allocations { + let txid = bitcoin::Txid::from_str(&allocation.owner.txid.to_hex()) + .expect("invalid txid"); + let is_spent = resolver + .resolve_spent_status(txid, allocation.owner.vout.into_u32().into()) + .expect("cannot find utxo"); + + if let Some(utxo) = wallet.utxo(allocation.owner) { + owners.push(AllocationDetail { + utxo: utxo.outpoint.to_string(), + value: AllocationValue::Value(allocation.value), + derivation: format!( + "/{}/{}", + utxo.derivation.terminal.app, utxo.derivation.terminal.index + ), + is_mine: true, + is_spent, + }); + } else { + owners.push(AllocationDetail { + utxo: allocation.owner.to_string(), + value: AllocationValue::Value(allocation.value), + derivation: default!(), + is_mine: false, + is_spent, + }); + } + } + } - let mut utxo = wallet - .utxos - .clone() - .into_iter() - .find(|utxo| { - utxo.derivation.terminal.app == iface_index && utxo.derivation.terminal == path - }) - .expect("invalid UTXO reference"); + if let Ok(allocations) = contract.data(owned.name.clone()) { + for allocation in allocations { + let txid = bitcoin::Txid::from_str(&allocation.owner.txid.to_hex()) + .expect("invalid txid"); + let is_spent = resolver + .resolve_spent_status(txid, allocation.owner.vout.into_u32().into()) + .expect("cannot find utxo"); + + if let Some(utxo) = wallet.utxo(allocation.owner) { + owners.push(AllocationDetail { + utxo: utxo.outpoint.to_string(), + value: AllocationValue::UDA(UDAPosition::with(allocation.value)), + derivation: format!( + "/{}/{}", + utxo.derivation.terminal.app, utxo.derivation.terminal.index + ), + is_mine: true, + is_spent, + }); + } else { + owners.push(AllocationDetail { + utxo: allocation.owner.to_string(), + value: AllocationValue::UDA(UDAPosition::with(allocation.value)), + derivation: default!(), + is_mine: false, + is_spent, + }); + } + } + } + } + } - wallet.utxos.remove(&utxo); - utxo.derivation.tweak = Some(tap_commit); - wallet.utxos.insert(utxo); + Ok(WatcherDetail { + contract_id: contract_id.to_string(), + allocations: owners, + }) } diff --git a/src/structs.rs b/src/structs.rs index 8740c92c..b63cac96 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -368,7 +368,7 @@ pub struct PsbtRequest { /// Bitcoin Fee pub fee: Option, /// TapTweak used to spend outputs based in tapret commitments - pub input_tweak: Option, + pub tapret: Option, } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -526,8 +526,10 @@ pub struct AllocationDetail { pub value: AllocationValue, /// Derivation Path pub derivation: String, - /// Derivation Path + /// My Allocation? pub is_mine: bool, + /// Allocation spent? + pub is_spent: bool, } #[derive(Serialize, Deserialize, Debug, Clone, Display)] diff --git a/tests/rgb.rs b/tests/rgb.rs index af1ef36a..f296722b 100644 --- a/tests/rgb.rs +++ b/tests/rgb.rs @@ -13,13 +13,14 @@ mod rgb { // mod collectibles; mod collectibles; mod fungibles; + mod import; mod issue; mod states; mod stress; + mod transfers; mod udas; pub mod utils; mod watcher; - mod import; } mod web { diff --git a/tests/rgb/integration/fungibles.rs b/tests/rgb/integration/fungibles.rs index 0d467248..df27983b 100644 --- a/tests/rgb/integration/fungibles.rs +++ b/tests/rgb/integration/fungibles.rs @@ -1,7 +1,7 @@ #![cfg(not(target_arch = "wasm32"))] use crate::rgb::integration::utils::{ create_new_invoice, create_new_psbt, create_new_transfer, issuer_issue_contract, - ISSUER_MNEMONIC, + ISSUER_MNEMONIC, OWNER_MNEMONIC, }; use bitmask_core::{ bitcoin::{save_mnemonic, sign_psbt_file}, @@ -16,10 +16,31 @@ async fn allow_beneficiary_accept_transfer() -> anyhow::Result<()> { &SecretString("".to_string()), ) .await?; - let issuer_resp = issuer_issue_contract("RGB20", 5, false, true, None).await?; - let owner_resp = create_new_invoice(issuer_resp.clone(), None).await?; - let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer_resp.clone()).await?; - let transfer_resp = &create_new_transfer(issuer_keys.clone(), owner_resp, psbt_resp).await?; + let owner_keys = save_mnemonic( + &SecretString(OWNER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + let issuer_resp = &issuer_issue_contract("RGB20", 5, false, true, None).await?; + let owner_resp = &create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 1, + owner_keys.clone(), + None, + Some(issuer_resp.clone().contract.legacy), + ) + .await?; + let psbt_resp = create_new_psbt( + &issuer_resp.contract_id, + &issuer_resp.iface, + &issuer_resp.issue_utxo, + issuer_keys.clone(), + None, + ) + .await?; + let transfer_resp = + &create_new_transfer(issuer_keys.clone(), owner_resp.clone(), psbt_resp).await?; let sk = issuer_keys.private.nostr_prv.to_string(); let request = SignPsbtRequest { diff --git a/tests/rgb/integration/states.rs b/tests/rgb/integration/states.rs index 9decde73..4e81c01f 100644 --- a/tests/rgb/integration/states.rs +++ b/tests/rgb/integration/states.rs @@ -55,14 +55,30 @@ async fn allow_get_fungible_contract_state_by_accept_cosign() -> anyhow::Result< &SecretString("".to_string()), ) .await?; - let issuer_resp = issuer_issue_contract("RGB20", 5, false, true, None).await?; - let owner_resp = create_new_invoice(issuer_resp.clone(), None).await?; - let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer_resp.clone()).await?; - let transfer_resp = &create_new_transfer(issuer_keys.clone(), owner_resp, psbt_resp).await?; + let issuer_resp = &issuer_issue_contract("RGB20", 5, false, true, None).await?; + let owner_resp = &create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 1, + owner_keys.clone(), + None, + Some(issuer_resp.clone().contract.legacy), + ) + .await?; + let psbt_resp = create_new_psbt( + &issuer_resp.contract_id, + &issuer_resp.iface, + &issuer_resp.issue_utxo, + issuer_keys.clone(), + None, + ) + .await?; + let transfer_resp = + &create_new_transfer(issuer_keys.clone(), owner_resp.clone(), psbt_resp).await?; // 2. Sign and Publish TX (Issuer side) let issuer_sk = issuer_keys.private.nostr_prv.to_string(); - let owner_sk = owner_keys.private.nostr_prv.to_string(); + let owner_sk = owner_keys.clone().private.nostr_prv.to_string(); let request = SignPsbtRequest { psbt: transfer_resp.psbt.clone(), descriptor: SecretString(issuer_keys.private.rgb_assets_descriptor_xprv.clone()), @@ -98,7 +114,7 @@ async fn allow_get_fungible_contract_state_by_accept_cosign() -> anyhow::Result< let watcher_name = "default"; let create_watch_req = WatcherRequest { name: watcher_name.to_string(), - xpub: owner_keys.public.watcher_xpub.clone(), + xpub: owner_keys.clone().public.watcher_xpub.clone(), force: true, }; create_watcher(&owner_sk, create_watch_req).await?; @@ -121,20 +137,35 @@ async fn allow_get_uda_contract_state_by_accept_cosign() -> anyhow::Result<()> { &SecretString("".to_string()), ) .await?; - let owner_keys = save_mnemonic( + let owner_keys = &save_mnemonic( &SecretString(OWNER_MNEMONIC.to_string()), &SecretString("".to_string()), ) .await?; - let issuer_resp = issuer_issue_contract("RGB21", 1, false, true, single).await?; - let owner_resp = create_new_invoice(issuer_resp.clone(), None).await?; - let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer_resp.clone()).await?; - let transfer_resp = &create_new_transfer(issuer_keys.clone(), owner_resp, psbt_resp).await?; + let owner_resp = &create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 1, + owner_keys.clone(), + None, + Some(issuer_resp.clone().contract.legacy), + ) + .await?; + let psbt_resp = create_new_psbt( + &issuer_resp.contract_id, + &issuer_resp.iface, + &issuer_resp.issue_utxo, + issuer_keys.clone(), + None, + ) + .await?; + let transfer_resp = + &create_new_transfer(issuer_keys.clone(), owner_resp.clone(), psbt_resp).await?; // 2. Sign and Publish TX (Issuer side) let issuer_sk = issuer_keys.private.nostr_prv.to_string(); - let owner_sk = owner_keys.private.nostr_prv.to_string(); + let owner_sk = owner_keys.clone().private.nostr_prv.to_string(); let request = SignPsbtRequest { psbt: transfer_resp.psbt.clone(), descriptor: SecretString(issuer_keys.private.rgb_udas_descriptor_xprv.clone()), @@ -170,7 +201,7 @@ async fn allow_get_uda_contract_state_by_accept_cosign() -> anyhow::Result<()> { let watcher_name = "default"; let create_watch_req = WatcherRequest { name: watcher_name.to_string(), - xpub: owner_keys.public.watcher_xpub.clone(), + xpub: owner_keys.clone().public.watcher_xpub.clone(), force: true, }; create_watcher(&owner_sk, create_watch_req).await?; diff --git a/tests/rgb/integration/stress.rs b/tests/rgb/integration/stress.rs index bc1cb684..9b2f8f86 100644 --- a/tests/rgb/integration/stress.rs +++ b/tests/rgb/integration/stress.rs @@ -159,8 +159,14 @@ async fn allow_issue_x_fungibles_witn_spend_utxos() -> anyhow::Result<()> { // issuer.contract_id, issuer.supply, issuer.issue_utxo // ); } - - let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer).await?; + let psbt_resp = create_new_psbt( + &issuer.contract_id, + &issuer.iface, + &issuer.issue_utxo, + issuer_keys.clone(), + None, + ) + .await?; let original_psbt = Psbt::from_str(&psbt_resp.psbt)?; let final_psbt = PartiallySignedTransaction::from(original_psbt); @@ -406,13 +412,15 @@ async fn allow_issue_x_uda_witn_spend_utxos() -> anyhow::Result<()> { let issuer_resp = issuer_issue_contract(iface, supply, false, true, None).await; issuer = issuer_resp?; contracts.insert(issuer.contract_id.clone(), issuer.supply); - // println!( - // "Contract #{i} ({}) : {} ({})", - // issuer.contract_id, issuer.supply, issuer.issue_utxo - // ); } - - let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer).await?; + let psbt_resp = create_new_psbt( + &issuer.contract_id, + &issuer.iface, + &issuer.issue_utxo, + issuer_keys.clone(), + None, + ) + .await?; let original_psbt = Psbt::from_str(&psbt_resp.psbt)?; let final_psbt = PartiallySignedTransaction::from(original_psbt); diff --git a/tests/rgb/integration/transfers.rs b/tests/rgb/integration/transfers.rs new file mode 100644 index 00000000..7f3b9694 --- /dev/null +++ b/tests/rgb/integration/transfers.rs @@ -0,0 +1,556 @@ +#![cfg(not(target_arch = "wasm32"))] +use bitmask_core::{ + bitcoin::{save_mnemonic, sign_psbt_file}, + rgb::{accept_transfer, create_watcher, get_contract}, + structs::{AcceptRequest, DecryptedWalletData, SecretString, SignPsbtRequest, WatcherRequest}, +}; + +use crate::rgb::integration::utils::{ + create_new_invoice, create_new_psbt, create_new_transfer, issuer_issue_contract, + ANOTHER_OWNER_MNEMONIC, ISSUER_MNEMONIC, OWNER_MNEMONIC, +}; + +#[tokio::test] +async fn allow_issuer_make_conseq_transfers() -> anyhow::Result<()> { + // 1. Issue and First Transfer (Issuer side) + let issuer_keys: DecryptedWalletData = save_mnemonic( + &SecretString(ISSUER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + let owner_keys = &save_mnemonic( + &SecretString(OWNER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + let issuer_resp = &issuer_issue_contract("RGB20", 5, false, true, None).await?; + let owner_resp = &create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 1, + owner_keys.clone(), + None, + Some(issuer_resp.clone().contract.legacy), + ) + .await?; + let psbt_resp = create_new_psbt( + &issuer_resp.contract_id, + &issuer_resp.iface, + &issuer_resp.issue_utxo, + issuer_keys.clone(), + None, + ) + .await?; + let transfer_resp = + &create_new_transfer(issuer_keys.clone(), owner_resp.clone(), psbt_resp.clone()).await?; + + // 2. Sign and Publish TX (Issuer side) + let issuer_sk = issuer_keys.private.nostr_prv.to_string(); + let request = SignPsbtRequest { + psbt: transfer_resp.psbt.clone(), + descriptor: SecretString(issuer_keys.private.rgb_assets_descriptor_xprv.clone()), + }; + let resp = sign_psbt_file(request).await; + assert!(resp.is_ok()); + + // 3. Accept Consig (Issuer Side) + let request = AcceptRequest { + consignment: transfer_resp.clone().consig, + force: false, + }; + let resp = accept_transfer(&issuer_sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + + // 4. Check Contract Balance (Issuer Side) + let contract_id = &issuer_resp.contract_id; + let resp = get_contract(&issuer_sk, contract_id).await; + assert!(resp.is_ok()); + + let issuer_contract = resp?; + assert_eq!(4, issuer_contract.balance); + + // 5. Create Second Invoice (Owner Side) + let owner_resp = create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 1, + owner_keys.clone(), + None, + None, + ) + .await?; + + // 6. Create Second Transfer (Issuer Side) + let new_alloc = issuer_contract + .allocations + .into_iter() + .find(|x| x.is_mine == true) + .unwrap(); + let psbt_resp = create_new_psbt( + &issuer_resp.contract_id, + &issuer_resp.iface, + &new_alloc.utxo, + issuer_keys.clone(), + None, + ) + .await?; + let transfer_resp = &create_new_transfer(issuer_keys.clone(), owner_resp, psbt_resp).await?; + let request = SignPsbtRequest { + psbt: transfer_resp.psbt.clone(), + descriptor: SecretString(issuer_keys.private.rgb_assets_descriptor_xprv.clone()), + }; + let resp = sign_psbt_file(request).await; + assert!(resp.is_ok()); + + // 7. Accept Consig (Issuer Side) + let request = AcceptRequest { + consignment: transfer_resp.clone().consig, + force: false, + }; + let resp = accept_transfer(&issuer_sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + + // 8. Check Contract Balance (Issuer Side) + let contract_id = &issuer_resp.contract_id; + let resp = get_contract(&issuer_sk, contract_id).await; + assert!(resp.is_ok()); + assert_eq!(3, resp?.balance); + + Ok(()) +} + +#[tokio::test] +async fn allow_owner_make_conseq_transfers() -> anyhow::Result<()> { + let issuer_keys: DecryptedWalletData = save_mnemonic( + &SecretString(ISSUER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + let owner_keys = &save_mnemonic( + &SecretString(OWNER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + + // 1. Issue and Create First Transfer (Issuer side) + let issuer_resp = &issuer_issue_contract("RGB20", 5, false, true, None).await?; + let owner_resp = &create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 2, + owner_keys.clone(), + None, + Some(issuer_resp.clone().contract.legacy), + ) + .await?; + let psbt_resp = create_new_psbt( + &issuer_resp.contract_id, + &issuer_resp.iface, + &issuer_resp.issue_utxo, + issuer_keys.clone(), + None, + ) + .await?; + let transfer_resp = + &create_new_transfer(issuer_keys.clone(), owner_resp.clone(), psbt_resp.clone()).await?; + + // 2. Sign and Publish TX (Issuer side) + let issuer_xprv = issuer_keys.private.rgb_assets_descriptor_xprv.clone(); + let request = SignPsbtRequest { + psbt: transfer_resp.psbt.clone(), + descriptor: SecretString(issuer_xprv), + }; + let resp = sign_psbt_file(request).await; + assert!(resp.is_ok()); + + // 3. Accept Consig (Issuer Side) + let issuer_sk = issuer_keys.private.nostr_prv.to_string(); + let request = AcceptRequest { + consignment: transfer_resp.clone().consig, + force: false, + }; + let resp = accept_transfer(&issuer_sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + + // 4. Create Watcher (Owner Side) + let owner_sk = owner_keys.private.nostr_prv.to_string(); + let create_watch_req = WatcherRequest { + name: "default".to_string(), + xpub: owner_keys.public.watcher_xpub.clone(), + force: true, + }; + create_watcher(&owner_sk, create_watch_req.clone()).await?; + + // 5. Accept Consig (Owner Side) + let request = AcceptRequest { + consignment: transfer_resp.clone().consig, + force: false, + }; + let resp = accept_transfer(&owner_sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + + // 6. Get Contract (Owner Side) + let contract_id = &issuer_resp.contract_id; + let resp = get_contract(&owner_sk, contract_id).await; + assert!(resp.is_ok()); + + let owner_contract = resp?; + assert_eq!(2, owner_contract.balance); + + // 7. Create Invoice (Issuer Side) + let issuer_invoice_resp = &create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 1, + issuer_keys.clone(), + None, + None, + ) + .await?; + + // 8. Create Transfer and Accept (Issuer Side) + let contract_utxo = owner_contract + .allocations + .into_iter() + .find(|alloc| alloc.is_mine && !alloc.is_spent) + .unwrap(); + + let psbt_resp = create_new_psbt( + &owner_contract.contract_id, + &owner_contract.iface, + &contract_utxo.utxo, + owner_keys.clone(), + None, + ) + .await?; + let transfer_resp = &create_new_transfer( + owner_keys.clone(), + issuer_invoice_resp.clone(), + psbt_resp.clone(), + ) + .await?; + let request = SignPsbtRequest { + psbt: transfer_resp.psbt.clone(), + descriptor: SecretString(owner_keys.private.rgb_assets_descriptor_xprv.clone()), + }; + let resp = sign_psbt_file(request).await; + assert!(resp.is_ok()); + + // 9. Accept Consig (Issuer Side) + let request = AcceptRequest { + consignment: transfer_resp.clone().consig, + force: false, + }; + let resp = accept_transfer(&owner_sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + + // 10. Check Contract Balance + let resp = get_contract(&owner_sk, contract_id).await; + assert!(resp.is_ok()); + + let owner_contract = resp?; + assert_eq!(1, owner_contract.balance); + + // 11. Create Invoice (Issuer Side) + let issuer_invoice_resp = &create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 1, + issuer_keys.clone(), + None, + None, + ) + .await?; + + // 12. Create Transfer and Accept (Issuer Side) + let contract_id = &issuer_resp.contract_id; + let resp = get_contract(&owner_sk, contract_id).await; + assert!(resp.is_ok()); + + let owner_contract = resp?; + assert_eq!(1, owner_contract.balance); + + let contract_utxo = owner_contract + .allocations + .into_iter() + .find(|alloc| alloc.is_mine && !alloc.is_spent) + .unwrap(); + + let psbt_resp = create_new_psbt( + &owner_contract.contract_id, + &owner_contract.iface, + &contract_utxo.utxo, + owner_keys.clone(), + None, + ) + .await?; + let transfer_resp = &create_new_transfer( + owner_keys.clone(), + issuer_invoice_resp.clone(), + psbt_resp.clone(), + ) + .await?; + let request = SignPsbtRequest { + psbt: transfer_resp.psbt.clone(), + descriptor: SecretString(owner_keys.private.rgb_assets_descriptor_xprv.clone()), + }; + let resp = sign_psbt_file(request).await; + assert!(resp.is_ok()); + + // 13. Accept Consig (Owner Side) + let request = AcceptRequest { + consignment: transfer_resp.clone().consig, + force: false, + }; + let resp = accept_transfer(&owner_sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + + // 14. Check Contract Balance (Owner Side) + let resp = get_contract(&owner_sk, contract_id).await; + assert!(resp.is_ok()); + + let owner_contract = resp?; + assert_eq!(0, owner_contract.balance); + Ok(()) +} + +#[tokio::test] +async fn allow_conseq_transfers_between_tree_owners() -> anyhow::Result<()> { + // 0. Retrieve all keys + let issuer_keys: DecryptedWalletData = save_mnemonic( + &SecretString(ISSUER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + let owner_keys = &save_mnemonic( + &SecretString(OWNER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + let another_owner_keys = &save_mnemonic( + &SecretString(ANOTHER_OWNER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + + // 1. Create All Watchers + let watcher_name = "default"; + let issuer_sk = issuer_keys.private.nostr_prv.to_string(); + let create_watch_req = WatcherRequest { + name: watcher_name.to_string(), + xpub: issuer_keys.public.watcher_xpub.clone(), + force: true, + }; + create_watcher(&issuer_sk, create_watch_req.clone()).await?; + + let owner_sk = owner_keys.private.nostr_prv.to_string(); + let create_watch_req = WatcherRequest { + name: watcher_name.to_string(), + xpub: owner_keys.public.watcher_xpub.clone(), + force: true, + }; + create_watcher(&owner_sk, create_watch_req.clone()).await?; + + let another_owner_sk = another_owner_keys.private.nostr_prv.to_string(); + let create_watch_req = WatcherRequest { + name: watcher_name.to_string(), + xpub: another_owner_keys.public.watcher_xpub.clone(), + force: true, + }; + create_watcher(&another_owner_sk, create_watch_req.clone()).await?; + + // 2. Issuer Contract + let issuer_resp = &issuer_issue_contract("RGB20", 5, false, true, None).await?; + + // 3. Owner Create Invoice + let owner_invoice = &create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 2, + owner_keys.clone(), + None, + Some(issuer_resp.clone().contract.strict), + ) + .await?; + + // 4. Create First Transfer + let psbt_resp = create_new_psbt( + &issuer_resp.contract_id, + &issuer_resp.iface, + &issuer_resp.issue_utxo, + issuer_keys.clone(), + None, + ) + .await?; + let transfer_resp = &create_new_transfer( + issuer_keys.clone(), + owner_invoice.clone(), + psbt_resp.clone(), + ) + .await?; + + let issuer_xprv = issuer_keys.private.rgb_assets_descriptor_xprv.clone(); + let request = SignPsbtRequest { + psbt: transfer_resp.psbt.clone(), + descriptor: SecretString(issuer_xprv), + }; + let resp = sign_psbt_file(request).await; + assert!(resp.is_ok()); + + // 5. Accept Consig (Issuer and Owner Side) + let all_sks = [issuer_sk.clone(), owner_sk.clone()]; + for sk in all_sks { + let request = AcceptRequest { + consignment: transfer_resp.clone().consig, + force: false, + }; + let accept_resp = accept_transfer(&sk, request).await; + assert!(accept_resp.is_ok()); + assert!(accept_resp?.valid); + } + + // 6. Check Contract Balances (Issuer Owner Side) + let contract_id = &issuer_resp.contract_id; + let resp = get_contract(&issuer_sk, contract_id).await; + assert!(resp.is_ok()); + + let issuer_contract = resp?; + assert_eq!(3, issuer_contract.balance); + + let resp = get_contract(&owner_sk, contract_id).await; + assert!(resp.is_ok()); + + let owner_contract = resp?; + assert_eq!(2, owner_contract.balance); + + // 7. Create 2 Invoices (Another Owner Side) + let another_invoice_1 = &create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 1, + another_owner_keys.clone(), + None, + Some(issuer_resp.clone().contract.strict), + ) + .await?; + + let another_invoice_2 = &create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 1, + another_owner_keys.clone(), + None, + None, + ) + .await?; + + // 8. Create Transfer and Accept (Issuer Side) + let issuer_xpriv = issuer_keys.private.rgb_assets_descriptor_xprv.clone(); + let issuer_utxo = issuer_contract + .allocations + .into_iter() + .find(|alloc| alloc.is_mine && !alloc.is_spent) + .unwrap(); + + let psbt_resp = create_new_psbt( + &issuer_contract.contract_id, + &issuer_contract.iface, + &issuer_utxo.utxo, + issuer_keys.clone(), + None, + ) + .await?; + let issuer_transfer_to_another_resp = &create_new_transfer( + issuer_keys.clone(), + another_invoice_1.clone(), + psbt_resp.clone(), + ) + .await?; + let request = SignPsbtRequest { + psbt: issuer_transfer_to_another_resp.psbt.clone(), + descriptor: SecretString(issuer_xpriv), + }; + let resp = sign_psbt_file(request).await; + assert!(resp.is_ok()); + + // 9. Create Transfer and Accept (Owner Side) + let owner_xpriv = owner_keys.private.rgb_assets_descriptor_xprv.clone(); + let owner_utxo = owner_contract + .allocations + .into_iter() + .find(|alloc| alloc.is_mine && !alloc.is_spent) + .unwrap(); + + let psbt_resp = create_new_psbt( + &owner_contract.contract_id, + &owner_contract.iface, + &owner_utxo.utxo, + owner_keys.clone(), + None, + ) + .await?; + let owner_transfer_to_another_resp = &create_new_transfer( + owner_keys.clone(), + another_invoice_2.clone(), + psbt_resp.clone(), + ) + .await?; + let request = SignPsbtRequest { + psbt: owner_transfer_to_another_resp.psbt.clone(), + descriptor: SecretString(owner_xpriv), + }; + let resp = sign_psbt_file(request).await; + assert!(resp.is_ok()); + + // 9. Accept Consig (Issuer and Another Owner Sides) + let all_sks = [issuer_sk.clone(), another_owner_sk.clone()]; + for sk in all_sks { + let request = AcceptRequest { + consignment: issuer_transfer_to_another_resp.clone().consig, + force: false, + }; + let resp = accept_transfer(&sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + } + + // 10. Accept Consig (Owner and Another Owner Sides) + let all_sks = [owner_sk.clone(), another_owner_sk.clone()]; + for sk in all_sks { + let request = AcceptRequest { + consignment: owner_transfer_to_another_resp.clone().consig, + force: false, + }; + let resp = accept_transfer(&sk, request).await; + assert!(resp.is_ok()); + assert!(resp?.valid); + } + + // 11. Verify Balances (All Sides) + let contract_id = &issuer_resp.contract_id; + let resp = get_contract(&issuer_sk, contract_id).await; + assert!(resp.is_ok()); + + let issuer_contract = resp?; + assert_eq!(2, issuer_contract.balance); + + let resp = get_contract(&owner_sk, contract_id).await; + assert!(resp.is_ok()); + + let owner_contract = resp?; + assert_eq!(1, owner_contract.balance); + + let resp = get_contract(&another_owner_sk, contract_id).await; + assert!(resp.is_ok()); + + let another_owner_contract = resp?; + assert_eq!(2, another_owner_contract.balance); + + Ok(()) +} diff --git a/tests/rgb/integration/udas.rs b/tests/rgb/integration/udas.rs index e11d85f1..09186de8 100644 --- a/tests/rgb/integration/udas.rs +++ b/tests/rgb/integration/udas.rs @@ -1,7 +1,7 @@ #![cfg(not(target_arch = "wasm32"))] use crate::rgb::integration::utils::{ create_new_invoice, create_new_psbt, create_new_transfer, get_uda_data, issuer_issue_contract, - ISSUER_MNEMONIC, + ISSUER_MNEMONIC, OWNER_MNEMONIC, }; use bitmask_core::{ bitcoin::{save_mnemonic, sign_psbt_file}, @@ -11,15 +11,35 @@ use bitmask_core::{ #[tokio::test] async fn allow_beneficiary_accept_transfer() -> anyhow::Result<()> { - let collectible = Some(get_uda_data()); + let single = Some(get_uda_data()); let issuer_keys = &save_mnemonic( &SecretString(ISSUER_MNEMONIC.to_string()), &SecretString("".to_string()), ) .await?; - let issuer_resp = issuer_issue_contract("RGB21", 1, false, true, collectible).await?; - let owner_resp = create_new_invoice(issuer_resp.clone(), None).await?; - let psbt_resp = create_new_psbt(issuer_keys.clone(), issuer_resp.clone()).await?; + let owner_keys = save_mnemonic( + &SecretString(OWNER_MNEMONIC.to_string()), + &SecretString("".to_string()), + ) + .await?; + let issuer_resp = &issuer_issue_contract("RGB21", 1, false, true, single).await?; + let owner_resp = create_new_invoice( + &issuer_resp.contract_id, + &issuer_resp.iface, + 1, + owner_keys, + None, + Some(issuer_resp.clone().contract.legacy), + ) + .await?; + let psbt_resp = create_new_psbt( + &issuer_resp.contract_id, + &issuer_resp.iface, + &issuer_resp.issue_utxo, + issuer_keys.clone(), + None, + ) + .await?; let transfer_resp = create_new_transfer(issuer_keys.clone(), owner_resp, psbt_resp).await?; let sk = issuer_keys.private.nostr_prv.to_string(); diff --git a/tests/rgb/integration/utils.rs b/tests/rgb/integration/utils.rs index 444461af..d173f5bf 100644 --- a/tests/rgb/integration/utils.rs +++ b/tests/rgb/integration/utils.rs @@ -20,10 +20,12 @@ use tokio::process::Command; pub const ISSUER_MNEMONIC: &str = "ordinary crucial edit settle pencil lion appear unlock left fly century license"; -#[allow(dead_code)] pub const OWNER_MNEMONIC: &str = "apology pull visa moon retreat spell elite extend secret region fly diary"; +pub const ANOTHER_OWNER_MNEMONIC: &str = + "circle hold drift unable own laptop age relax degree next alone stage"; + #[allow(dead_code)] pub async fn start_node() { let path = env::current_dir().expect("oh no!"); @@ -223,15 +225,14 @@ pub async fn import_new_contract( } pub async fn create_new_invoice( - issuer_resp: IssueResponse, + contract_id: &str, + iface: &str, + amount: u64, + owner_keys: DecryptedWalletData, params: Option>, + contract: Option, ) -> Result { - let owner_keys = save_mnemonic( - &SecretString(OWNER_MNEMONIC.to_string()), - &SecretString("".to_string()), - ) - .await?; - let descriptor_pub = match issuer_resp.iface.as_str() { + let descriptor_pub = match iface { "RGB20" => owner_keys.public.rgb_assets_descriptor_xpub.clone(), "RGB21" => owner_keys.public.rgb_udas_descriptor_xpub.clone(), _ => owner_keys.public.rgb_assets_descriptor_xpub.clone(), @@ -240,21 +241,22 @@ pub async fn create_new_invoice( // Create Watcher let sk = owner_keys.private.nostr_prv.clone(); - let contract_type = match issuer_resp.iface.as_str() { + let contract_type = match iface { "RGB20" => AssetType::RGB20, "RGB21" => AssetType::RGB21, _ => AssetType::Contract, }; - // Import Contract - let import_req = ImportRequest { - import: contract_type, - data: issuer_resp.contract.legacy, - }; - - let resp = import(&sk, import_req).await; - assert!(resp.is_ok()); + if let Some(contract) = contract { + // Import Contract + let import_req = ImportRequest { + import: contract_type, + data: contract, + }; + let resp = import(&sk, import_req).await; + assert!(resp.is_ok()); + } // Create Invoice let owner_address = &owner_vault .lock() @@ -273,9 +275,9 @@ pub async fn create_new_invoice( let params = params.unwrap_or_default(); let invoice_req = InvoiceRequest { - contract_id: issuer_resp.contract_id, - iface: issuer_resp.iface, - amount: 1, + contract_id: contract_id.to_owned(), + iface: iface.to_owned(), + amount: amount, seal, params, }; @@ -284,12 +286,15 @@ pub async fn create_new_invoice( } pub async fn create_new_psbt( - issuer_keys: DecryptedWalletData, - issuer_resp: IssueResponse, + contract_id: &str, + iface: &str, + owner_utxo: &str, + owner_keys: DecryptedWalletData, + tweak: Option, ) -> Result { // Get Allocations let watcher_name = "default"; - let sk = issuer_keys.private.nostr_prv.clone(); + let sk = owner_keys.private.nostr_prv.clone(); let resp = watcher_details(&sk, watcher_name).await; assert!(resp.is_ok()); @@ -299,12 +304,12 @@ pub async fn create_new_psbt( for contract_allocations in watcher_details .contracts .into_iter() - .filter(|x| x.contract_id == issuer_resp.contract_id) + .filter(|x| x.contract_id == contract_id) { let allocations: Vec = contract_allocations .allocations .into_iter() - .filter(|a| a.is_mine && a.utxo == issuer_resp.issue_utxo) + .filter(|a| a.is_mine && a.utxo == owner_utxo) .collect(); if let Some(allocation) = allocations.into_iter().next() { @@ -314,13 +319,13 @@ pub async fn create_new_psbt( } } - let descriptor_pub = match issuer_resp.iface.as_str() { - "RGB20" => issuer_keys.public.rgb_assets_descriptor_xpub.clone(), - "RGB21" => issuer_keys.public.rgb_udas_descriptor_xpub.clone(), - _ => issuer_keys.public.rgb_assets_descriptor_xpub.clone(), + let descriptor_pub = match iface { + "RGB20" => owner_keys.public.rgb_assets_descriptor_xpub.clone(), + "RGB21" => owner_keys.public.rgb_udas_descriptor_xpub.clone(), + _ => owner_keys.public.rgb_assets_descriptor_xpub.clone(), }; - assert_eq!(asset_utxo, issuer_resp.issue_utxo); + assert_eq!(asset_utxo, owner_utxo); let req = PsbtRequest { descriptor_pub: SecretString(descriptor_pub), asset_utxo: asset_utxo.to_string(), @@ -328,25 +333,25 @@ pub async fn create_new_psbt( change_index: None, bitcoin_changes: vec![], fee: None, - input_tweak: None, + tapret: tweak, }; create_psbt(&sk, req).await } pub async fn create_new_transfer( - issuer_keys: DecryptedWalletData, - owner_resp: InvoiceResponse, + owner_keys: DecryptedWalletData, + invoice_resp: InvoiceResponse, psbt_resp: PsbtResponse, ) -> Result { // Get Allocations let transfer_req = RgbTransferRequest { psbt: psbt_resp.psbt, - rgb_invoice: owner_resp.invoice, + rgb_invoice: invoice_resp.invoice, terminal: psbt_resp.terminal, }; - let sk = issuer_keys.private.nostr_prv.clone(); + let sk = owner_keys.private.nostr_prv.clone(); transfer_asset(&sk, transfer_req).await } diff --git a/tests/rgb/unit/psbt.rs b/tests/rgb/unit/psbt.rs index 21168aa5..1ac22495 100644 --- a/tests/rgb/unit/psbt.rs +++ b/tests/rgb/unit/psbt.rs @@ -30,6 +30,7 @@ async fn allow_create_psbt_file() -> anyhow::Result<()> { vec![], fee, None, + None, &tx_resolver, ); assert!(psbt.is_ok()); diff --git a/tests/rgb/web/imports.rs b/tests/rgb/web/imports.rs index 7844dc9f..ad4c7ef2 100644 --- a/tests/rgb/web/imports.rs +++ b/tests/rgb/web/imports.rs @@ -211,6 +211,6 @@ async fn asset_transfer() { let vault_details: FundVaultDetails = json_parse(&vault_details); } -const FUNGIBLE_CONTRACT: &str = "0100000000030300cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e4300100d007b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100d107b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010001d007010800c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b103030001000100d00701000100d1070100010001d0070100ffff000001d007c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10001d0070100ffff01d0070100ffff0037000017acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd010b524742436f6e7472616374044e616d65050198db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d81bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0107426974636f696e0554784f757406020576616c7565cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00c7363726970745075626b65794a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba1df1d11643dd30bf0b583883dfa61289186277ace4ad075e3c67ac0b83802eaa01035374640a486578446563436170730310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e4623bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0107426974636f696e095369675363726970740501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c3027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000403719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac600040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e38fd0b174ca8528da005d978de7dd5a2a763bb67e42ca25b935edf451344229e01035374640a416c706861536d616c6c031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e00050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d104693e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100000000000000000ffff0000000000004a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba0107426974636f696e0c5363726970745075626b65790501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c52740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560107426974636f696e084f7574706f696e7406020474786964b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab404766f7574fd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d5577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b000360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377f55accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b01035374640e41736369695072696e7461626c65035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e58a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066170000445cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80600085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b0100000000000000080000000000000060fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec010b524742436f6e74726163740b41737365744e616d696e670603067469636b657292e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506046e616d6517acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd0764657461696c733719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac661cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a25510000161dac6b5168357edbd878765f0382f79d864835c01c7e3a0d0747a235404c3ba010353746408416c7068614e756d033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a66ff6ddb2093d3e48033bbd707da2588df6a93d25b7d419c0592cadb31e8a2da0107426974636f696e02547806040776657273696f6e6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e8863206696e70757473e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba076f75747075747376ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f3086c6f636b54696d656f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e886320107426974636f696e055478566572050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066176c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110000086f0cbcc3130d8fdbd168f60ebb2477f344d85659ca1fc56d84b235072b67c74501035374640e416c7068614e756d4c6f64617368033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a6f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b0107426974636f696e084c6f636b54696d650501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253175b7c2e75f4dbfc3728201bc72c62986a08f2734cb3e50f32e6aad2f21343f5a010353746409416c70686143617073031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a76ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f300081bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0000000000000000ffffffffffffffff8a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffff0000000000008df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40107426974636f696e045478496e06040a707265764f757470757452740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560973696753637269707423bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0873657175656e6365bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff7077769746e657373bd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff791281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469010b524742436f6e74726163740744657461696c730501d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f92e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506010b524742436f6e7472616374065469636b657205015cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80698db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d800085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b01000000000000002800000000000000a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffffffffffffffffa788a36d6e35c945b224869165f2844711784f55b6b484b2f21f35397170ad8401035374640255340310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fae6894c8d85e1f4b6e7a31dabf56f6a09c1f423f6ce5fd49ea56bc025cb4f22301035374640c416c7068614e756d44617368033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7ab0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a5400073027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9962000b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010b524742436f6e74726163741152696361726469616e436f6e747261637405013e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd8989010b524742436f6e747261637412446976697369626c654173736574537065630602066e616d696e6760fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec09707265636973696f6ec554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab40107426974636f696e04547869640501b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54b9ef64121db10df182d4df713abb2b2e97a73f8f9c116f81f54577c3e0bf015b010353746403446563030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80010b524742436f6e74726163740f50726f6f664f6652657365727665730602047574786fb1e43bec82e3821b2d7ccee89a7d213da8b77eea0518bcfa4f6d6f8dfe0296de0570726f6f668a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caaebbd8604f99b5c9047de07d559069a286d27c94143106e2f5eae266ae44f7168701035374640c416c706861436170734e756d0324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5abd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff70107426974636f696e075769746e6573730501f5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c548bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff70107426974636f696e055365714e6f0501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5010b524742436f6e747261637409507265636973696f6e03130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f12c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b1000000cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e430010b524742436f6e74726163740954696d657374616d70050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c752606617cb958efe9c6d304f13222e2a4907124e86e7ea1c5a74e24c3e2235f6c4d2a9a501035374640b486578446563536d616c6c0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00107426974636f696e045361747305016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b11d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100100000000000000ff00000000000000e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000004e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba00088df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40000000000000000fffffffffffffffff27e112e62134308df24f66cd6a133e473d72977d65f49467f1fd8a4d92a13c7010353746404426f6f6c03020566616c736500047472756501f41f2a6324dcada5162bb3034f7c2a19ad40b9124fb467e44c5a0d772c430d8e010353746405416c7068610334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7af5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c5480008a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe0000000000000000fffffffffffffffff82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c0107426974636f696e0b53637269707442797465730501a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fefd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d0107426974636f696e04566f75740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253100015650fb29bac1c7616f976727b1e81234887ad96e7056f5a3cc99e4a8378b31480c00035247420300d0d007000000010004d0075650fb29bac1c7616f976727b1e81234887ad96e7056f5a3cc99e4a8378b3148000001dd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce900055247423230060c6275726e6564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a0001076372656174656401cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001000c697373756564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a00010e7265706c61636564537570706c7901827e39faac0b9c30a347c9acc0806857daf002600a077285bdc792974b45461a0001047370656301b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100057465726d7301b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae37798610700100050a61737365744f776e657202000001096275726e45706f636801010000096275726e52696768740101000112696e666c6174696f6e416c6c6f77616e6365020100010b75706461746552696768740101000000010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b704076372656174656400010001000c697373756564537570706c79000100010004737065630001000100057465726d730001000100040a61737365744f776e6572000000ffff096275726e45706f6368000000010012696e666c6174696f6e416c6c6f77616e6365000000ffff0b75706461746552696768740000000100000301030406044275726e0101f4bdcb47aa7db1caab5656f482e6788f22cf4534f93d506cdb350e13b9d0d9eb010c6275726e6564537570706c79000100010001047573656401096275726e526967687401000100010666757475726501096275726e52696768740000010000030103050005497373756501010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7010c697373756564537570706c7900010001000104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff000401030406010b62656e6566696369617279094f70656e45706f636801000001047573656401096275726e45706f63680100010002096275726e52696768740001000100046e65787401096275726e45706f636800000100000001096275726e52696768740652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265075265706c6163650101f4bdcb47aa7db1caab5656f482e6788f22cf4534f93d506cdb350e13b9d0d9eb010e7265706c61636564537570706c79000100010001047573656401096275726e526967687401000100020b62656e6566696369617279010a61737365744f776e65720000ffff0666757475726501096275726e526967687400000100000401020305010b62656e6566696369617279085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000102010b62656e65666963696172790031e4e2b06ffac24c5455a677c387081de1697ebb91ba71ef38825fc9301bc80301085472616e7366657200d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bddd714b50abad11b6872bc979472f7f8b7fa76a93aeca411b2358e2418b3e3ce90303000763726561746564d0070473706563d107057465726d7301d0070b62656e65666963696172790001d007085472616e7366657200000000d5ae1e7a375e11628ac4a5f0a0b1b68eca894cf4f656da7337fb190b811584bd8000000303000100040000000000d00701000c00044449424104444942410002d1070100060004004449424101d00701010003010f84aebd6b9d58f808b0eb282c1d3802237a0f4477909b60fa69ef55caebdc95010000003d3cea3df2e5f455080500000000000000f6a514bcbf244213c0974ff756cb38ef8f085bbff24a3753f806f04d99556ea20000000000000000000000000000"; +const FUNGIBLE_CONTRACT: &str = "0100000000030300596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b0100d00799624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100d10718cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010001d007010800d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c03030001000100d00701000100d1070100010001d0070100ffff000001d007d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0001d0070100ffff01d0070100ffff003c000001196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e870501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed707fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a5081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffffffffffffffff0b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0602047574786fe86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c5060570726f6f66f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef083815dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465087a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed91140000000000000000ffffffffffffffff181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb1086015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410100000000000000080000000000000018cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010501560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f9391551541cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904200401deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da8915900501e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e21e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac943750501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed72a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd071cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904220002d2519390702d9a3484b79e289e7bbf2a8cad7fb5d2bc0a5f8471dba6fa3c03c031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a30a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe7680807fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a50000000000000000ffffffffffffffff332de353e616da0cb6394a23d10773fae94ff131f4fe216b2d0001bff1c7b2fb06040776657273696f6ea87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e06696e7075747315dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465076f7574707574738ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca086c6f636b54696d6535da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c339840868f9caa65acd0874d1a06eb2ee2614cdcd537f77615c836cb9a613d93033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a35da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed73c8add893836f8c04c073d1f454d9525cf96a7d7557296fa663ddbaaefa843940334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4050163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc75014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d4050184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515408fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780000000000000000ffff000000000000596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f5be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269050107fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a55ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f00085d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f2203130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f126015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a618622d17baef06602dfe775c980e0b36b6ebae8090d8075f7513bec4b93f64d03020566616c73650004747275650163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a08fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780100000000000000ff0000000000000065eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a06020576616c756597f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b0c7363726970745075626b6579cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea490436632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f0044728ea68a97de7420f62a5969b04b872604bf45d6df38959c7e26e7a72490e4ad033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a7a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed911406040a707265764f7574707574e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50609736967536372697074cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec940873657175656e636501196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e87077769746e657373ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb258057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a50501181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000028000000000000008ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca0865eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a0000000000000000ffffffffffffffff97f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b05015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f99624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10602066e616d696e67de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff58609707265636973696f6e5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f229e14cce6b185cca477ba44634bfa2c5871a97e0c32b7aec1df6a94522a9319c70310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655605012a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdda5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed70004a62e384a135184183b9da6b9796b06e88c75c6803139dd391148ea049ae3d7e10310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66a87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48fbaa0e3fcab9d55d168bb1e26837153afe89f83a27e0498554d3963f6431fd3f4033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7abc2891b1c66ac5f5e61059a32077daa82333a1435bd34608b30b03fc017d9545030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d651deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da891590c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb32544866340360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377fcae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea4904305015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc705013f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec9405015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0000da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b408c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb325448663401000000000000004000000000000000de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff5860603067469636b65728057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5046e616d655014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d40764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0501da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b4e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50606020474786964a38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655604766f757421e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac94375eedec3ebaa08fb010f2f96e17a0e039ad87fe60771a7301f8c5e88995d05676b0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e46ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb25050130a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe768f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffff000000000000f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7afb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc694206030474797065e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0773756274797065c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c0763686172736574c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298cfba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78010001bab043436d5163f8872caa19c3c863c0878364fe504a1c6dcfb0f2d2c62dcfdb0c00035247420300d0d007000000010004d007bab043436d5163f8872caa19c3c863c0878364fe504a1c6dcfb0f2d2c62dcfdb0000019abcb19a89c3e955b796ff9044c1078e81ab142c309d8524c774094a1835838f00055247423230060c6275726e6564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e840001076372656174656401596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b01000c697373756564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e8401010e7265706c61636564537570706c7901888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84000104737065630199624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100057465726d730118cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010100050a61737365744f776e657202000001096275726e45706f636801010000096275726e52696768740101000112696e666c6174696f6e416c6c6f77616e6365020100010b7570646174655269676874010100000001467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b04076372656174656400010001000c697373756564537570706c79000100010004737065630001000100057465726d730001000100040a61737365744f776e6572000000ffff096275726e45706f6368000000010012696e666c6174696f6e416c6c6f77616e6365000000ffff0b75706461746552696768740000000100000301030406044275726e0101318ecaa072870bd95230a9515a6aaa14982bac9e3fb15ea2528eb0405227a7a1010c6275726e6564537570706c79000100010001047573656401096275726e526967687401000100010666757475726501096275726e5269676874000001000003010305000549737375650101467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b010c697373756564537570706c7900010001000104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff000401030406010b62656e6566696369617279094f70656e45706f636801000001047573656401096275726e45706f63680100010002096275726e52696768740001000100046e65787401096275726e45706f636800000100000001096275726e52696768740652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265075265706c6163650101318ecaa072870bd95230a9515a6aaa14982bac9e3fb15ea2528eb0405227a7a1010e7265706c61636564537570706c79000100010001047573656401096275726e526967687401000100020b62656e6566696369617279010a61737365744f776e65720000ffff0666757475726501096275726e526967687400000100000401020305010b62656e6566696369617279085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000102010b62656e656669636961727900a1879e8f56bdd6fd8ca323b94f39e060643aa69a39219194d60c4c8a7c7b01c801085472616e7366657200c70931fdf90384c1f4b4f34b2543e80876e35dbf0f15b567ccec8b340b811cc99abcb19a89c3e955b796ff9044c1078e81ab142c309d8524c774094a1835838f0303000763726561746564d0070473706563d107057465726d7301d0070b62656e65666963696172790001d007085472616e7366657200000000c70931fdf90384c1f4b4f34b2543e80876e35dbf0f15b567ccec8b340b811cc98000000303000100040000000000d00701000c00044449424104444942410002d1070100060004004449424101d007010100030177326df3704bdca90c1ad9b33a2e064e88d0cd631bb71ab15619481c2ca92ce7010000002c46352ea481d989080500000000000000073dbed09d95db3df59f8ad1e443bbd0d76f31d804b7eca91f08ab85b1a94ead0000000000000000000000000000"; -const UDA_CONTRACT: &str = "0100000000050300cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001003408b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd898901003508b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae37798610700100360806df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c01003808869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f60100013408025d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa81000c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b105030001000100340801000100350801000100360800000100380800000100013408010001000000013408c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b100013408010001000134080100010000580000017447c77d2367544618e2aaf4e680659b9df075544650b5a4bbab699ea258c800040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d651da55835280aba3b02d1b5d02fc3fc47c267e8ed85554b0e7d13beed5c132b30065602cf1069e5dcfccabc7fd98ca570ce4eb972bddfb8c63633483dd519c19d00085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b0100000000000000400000000000000006df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c0105524742323109546f6b656e44617461060805696e646578d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d7664067469636b6572d669d8d150ff6a2e7486568b066e2fb43e4efe6aab93d103d8f559d14a6ccd15046e616d65017447c77d2367544618e2aaf4e680659b9df075544650b5a4bbab699ea258c80764657461696c73181998eeb65f373753d54b4983424050c38cb464d587d6a3741a13c69abfdc1007707265766965774cc79dab63f53b172bd53af42d3c1b9e36fdc5ba19ec625dcf99cf9ee6d23178056d65646961ba7da437dd2009266764a53302be280bec57a35edea906c42185c96e1a1d4e840b6174746163686d656e74730f1b2b5d80322340d1064fcfc7b82c98002836666b576b1eb7baf1a2d2756cff0872657365727665730c90d2700887419382cbcbd28c78d7c1b112602e4438551c3ca58ae68a975cbc0718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7010552474232310949737375654d65746106010872657365727665734d09d713e21e9bbabd91ffe3ac096102dcfe3ed8994f7089158532a139a024bb09317e1367c0edbbfffb675b5329d6554a0ec62580c5e5a5215af318270a88b3010552474232310d4f776e65644672616374696f6e05016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110c90d2700887419382cbcbd28c78d7c1b112602e4438551c3ca58ae68a975cbc00040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65affcae68cd21c376584c7b4a68de738dfad6386a7d6d3a7bbb348227976d14f80f1b2b5d80322340d1064fcfc7b82c98002836666b576b1eb7baf1a2d2756cff000a0001a84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e20000000000000000140000000000000017acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd010b524742436f6e7472616374044e616d65050198db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d8181998eeb65f373753d54b4983424050c38cb464d587d6a3741a13c69abfdc1000040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65b360cb3d1a1ce2559dd5cc11d2b3164467211559b80a239b16d081f394fa5b531bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0107426974636f696e0554784f757406020576616c7565cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00c7363726970745075626b65794a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba1da55835280aba3b02d1b5d02fc3fc47c267e8ed85554b0e7d13beed5c132b3000050117acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd1df1d11643dd30bf0b583883dfa61289186277ace4ad075e3c67ac0b83802eaa01035374640a486578446563436170730310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e4623bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0107426974636f696e095369675363726970740501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c3027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000403719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac600040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e38fd0b174ca8528da005d978de7dd5a2a763bb67e42ca25b935edf451344229e01035374640a416c706861536d616c6c031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a397f40dda5a1de9387631c2803e9e521701724cbb5f72c0c9c499528cb11255e00050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d104693e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100000000000000000ffff000000000000470ad9ae9cbc8fa7428330b0c0a4fb32d1f9fc30a94eaa4b3c41145b849a56e9000501a84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e2497c7eb9391a079a38d92afdde2e4eec03a9a37987201d5ab5b14d45c17b250d010552474232310d456e67726176696e67446174610602096170706c696564546fd3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d766407636f6e74656e747b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da24a5f3eb8ee47b0cbe31c346128915acb0158f3f3f0f8331a3606008476c5a4ba0107426974636f696e0c5363726970745075626b65790501f82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c4cc79dab63f53b172bd53af42d3c1b9e36fdc5ba19ec625dcf99cf9ee6d2317800040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d656022af4d5e00c75978b1d60421997e0b227b395dce5e52da8e030b6ae9174a444d09d713e21e9bbabd91ffe3ac096102dcfe3ed8994f7089158532a139a024bb0009ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc800000000000000000ffff0000000000004f46dce8279430081e45f623d0d618ed7f52efb553bc241b0d2ae7ec601c1a5c01055247423231094d6564696154797065060304747970655538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa0773756274797065b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b90763686172736574b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b952740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560107426974636f696e084f7574706f696e7406020474786964b9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab404766f7574fd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d5538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa010552474232310c4d656469615265674e616d650501065602cf1069e5dcfccabc7fd98ca570ce4eb972bddfb8c63633483dd519c19d5577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b000360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377f55accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b01035374640e41736369695072696e7461626c65035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e58a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066170000445cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb80600085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b010000000000000008000000000000005d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa810010552474232310a416c6c6f636174696f6e0502d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d766409317e1367c0edbbfffb675b5329d6554a0ec62580c5e5a5215af318270a88b36022af4d5e00c75978b1d60421997e0b227b395dce5e52da8e030b6ae9174a440005017b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da260fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec010b524742436f6e74726163740b41737365744e616d696e670603067469636b657292e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506046e616d6517acabd632abeb9176b659a5e40070601e073b9446eb50b8bda73a1c8b0e1cbd0764657461696c733719145aa2f1dc0634e5e045768ffd446b1cccc53ac35451e988cecfb0e82ac661cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a25510000161dac6b5168357edbd878765f0382f79d864835c01c7e3a0d0747a235404c3ba010353746408416c7068614e756d033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a66ff6ddb2093d3e48033bbd707da2588df6a93d25b7d419c0592cadb31e8a2da0107426974636f696e02547806040776657273696f6e6963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e8863206696e70757473e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba076f75747075747376ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f3086c6f636b54696d656f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b695eb06afff78803151c5c7c1620648f52dca30526ce3ec3fea1ad7fcab75a8a000855accd0bd38507ff95b514cf33bc3bb04b37b3ced16d7074f4d27ee769f8708b010000000000000014000000000000006963e1597f9636af6af38943ca63cadde22fb833cbc3f64b0591e691a5e886320107426974636f696e055478566572050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c7526066176c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b110000086f0cbcc3130d8fdbd168f60ebb2477f344d85659ca1fc56d84b235072b67c74501035374640e416c7068614e756d4c6f64617368033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a6f23e8a03955547d9bd76db47bb7e5eea3792d5f8f223c790cc2b5eed658c09f0005015538b67d45c93d6f2da458d1d916b8d64fc53a46761cb718c95373366b5d94fa6f76bda4fc01f33b4f968c519d5be6cc94b220e87cb27c17be7968be175bb23b0107426974636f696e084c6f636b54696d650501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c18959253175b7c2e75f4dbfc3728201bc72c62986a08f2734cb3e50f32e6aad2f21343f5a010353746409416c70686143617073031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a76ff3d6d8f5cb91cb3895e79b643a74b4e6e0b80f0cfb81e489a3dbdb08e73f300081bf1fedf1c6912c748abc2001cfe4168109a1737c8aff7146994121a567c869e0000000000000000ffffffffffffffff7b9ed74cfbec6bab5ee344f08faddbf29cedb0d5767ac93c7725a9cd9ddc5da2010552474232310d456d6265646465644d65646961060204747970654f46dce8279430081e45f623d0d618ed7f52efb553bc241b0d2ae7ec601c1a5c04646174618a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f6010552474232310e4174746163686d656e74547970650602026964cd2a948954a0dc1dd1a4e04145245638af3f544c133c68bf1af183cb3346668a046e616d659819b0f8b92eac0f19205791b5016c23f78f78560bb47d74e266a9c24b0cf33e8a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caae00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffff0000000000008aa05647e0f89c231194d76e4f776ef7d3255028c484cb63a8a68f7d0251695e00050192e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be8429835068df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40107426974636f696e045478496e06040a707265764f757470757452740f7fe68e10921f5174f59dde088a63673067fca4a7cc7c43a05272c4f4560973696753637269707423bffe394238a37d5b5e3bbfb20d089bb1a70b99f622a41b812792b30455fefa0873657175656e6365bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff7077769746e657373bd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff79048212cad2ed6e09a3e853c904f71889286e17ec23d0a3b6326ecee721b7b9901055247423231054572726f720308106672616374696f6e4f766572666c6f77010e6e6f6e457175616c56616c756573020c696e76616c696450726f6f660314696e73756666696369656e7452657365727665730415697373756545786365656473416c6c6f77616e636506126e6f6e4672616374696f6e616c546f6b656e07126e6f6e456e6772617661626c65546f6b656e0815696e76616c69644174746163686d656e74547970650991281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469010b524742436f6e74726163740744657461696c730501d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f92e75ca87a0d45ef319dd973902d8da2d2682e4c7e23df479bfe7be842983506010b524742436f6e7472616374065469636b657205015cd0c3c0db677e225d50c0cd55a38fd2a79d3a29d625e34f78dfd6166c3cb8069819b0f8b92eac0f19205791b5016c23f78f78560bb47d74e266a9c24b0cf33e010552474232310e4174746163686d656e744e616d650501695eb06afff78803151c5c7c1620648f52dca30526ce3ec3fea1ad7fcab75a8a98db5d005b4983079dbbc8eec042032354b8eab68cccd526231e94adde72a8d800085577ee213895eed3a4a4e822db7cf6078f4b5e20d77270ba3c10bf8973c6cd4b01000000000000002800000000000000a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe00083027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9960000000000000000ffffffffffffffffa788a36d6e35c945b224869165f2844711784f55b6b484b2f21f35397170ad8401035374640255340310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa84e42c98c2be1e89fe5f0464597a8c091af6c1199f58d0eaaf0513ad8e9b3e2010552474232310a4174746163686d656e7406020474797065869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f606646967657374b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54ae6894c8d85e1f4b6e7a31dabf56f6a09c1f423f6ce5fd49ea56bc025cb4f22301035374640c416c7068614e756d44617368033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7aaffcae68cd21c376584c7b4a68de738dfad6386a7d6d3a7bbb348227976d14f8000501ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a5400073027c5692319cc0ab919cecf42d1ce570c0a9acf723f4c7acaedd21ba7f5a9962000b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010b524742436f6e74726163741152696361726469616e436f6e747261637405013e558ffa0f0c38c22b61be4d110b893694d51c534c706f348af313251ec90336b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd8989010b524742436f6e747261637412446976697369626c654173736574537065630602066e616d696e6760fa8750a370b8274fd9a1c459fa1643fc7f90618c3910c6fe5cfc4d4f9691ec09707265636973696f6ec554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5b360cb3d1a1ce2559dd5cc11d2b3164467211559b80a239b16d081f394fa5b5300050191281bb3098255a02b46e8f68e9e50bf23a4f3797505a13d54ffe0a836d10469b6082cb1752c81bcf05bda217408903c0815ca0fb9e08c11e92cff4f3a5e50b900040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d656f23e8a03955547d9bd76db47bb7e5eea3792d5f8f223c790cc2b5eed658c09fb9a1e724481f322cbf738c7a6f8fc2f8a2148f460d97dc3a1249aa4300556ab40107426974636f696e04547869640501b0624361bcb1bf36e327d1e6a72d988ac1eb2a742622c67dbca34d4b3e022a54b9ef64121db10df182d4df713abb2b2e97a73f8f9c116f81f54577c3e0bf015b010353746403446563030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539ba03a26a9430b4c6b220e470f2bdbcd8623a0c7fb8391ac4158e5ddecb76bc80010b524742436f6e74726163740f50726f6f664f6652657365727665730602047574786fb1e43bec82e3821b2d7ccee89a7d213da8b77eea0518bcfa4f6d6f8dfe0296de0570726f6f668a1ba799463b3b3ae310d62396d627c8c6f5d0a6074bd90f3cd0f042a892caaeba7da437dd2009266764a53302be280bec57a35edea906c42185c96e1a1d4e8400040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d65470ad9ae9cbc8fa7428330b0c0a4fb32d1f9fc30a94eaa4b3c41145b849a56e9bbd8604f99b5c9047de07d559069a286d27c94143106e2f5eae266ae44f7168701035374640c416c706861436170734e756d0324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5abd4ffaafde95851c3384a87c93ee98c910df7d155654abb6d319a1b365dd3ff70107426974636f696e075769746e6573730501f5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c548bd59c9dc84217b547087940dd8a829bd6fd7fb7113b5f23f64786819e9a6aff70107426974636f696e055365714e6f0501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c1f252f38965138fc5cb730e49eda0f7f792ed6b88b2e17739d6410d251b1514010552474232310a4974656d73436f756e740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531c554138ee503e5eeaeae035a3039fc99c207d2759d11ec839d848825f8574ca5010b524742436f6e747261637409507265636973696f6e03130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f12c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b1000000cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e430010b524742436f6e74726163740954696d657374616d70050158a6a0b2462ddc493d1047be0d6406dc72d503e86f9a843c0095b7c752606617cb958efe9c6d304f13222e2a4907124e86e7ea1c5a74e24c3e2235f6c4d2a9a501035374640b486578446563536d616c6c0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66cc178d8a6859517ccffb2eef1903bded5ed318e877cdba7c95690ca161cd35b00107426974636f696e045361747305016c6376cfea59038c2885777c2750ca4fe1383eb9d9077afb068bab15c30b1b11cd2a948954a0dc1dd1a4e04145245638af3f544c133c68bf1af183cb3346668a000001d227605b657e591b4ff6556438b2cc9295a23f901591429214103e88dca98c6f000861cd903df3b4fbb4d828d35c53f976e3f81dc9e11820b2aa76661e4d28a255100100000000000000ff00000000000000d3846192a4f34491e64326e1dc7b4614d75da5b07bf4a278446a62fee62d7664010552474232310a546f6b656e496e6465780501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531d669d8d150ff6a2e7486568b066e2fb43e4efe6aab93d103d8f559d14a6ccd1500040200046e6f6e65c6bdee62481531f0f5e0758cda686053c050c4fc4ad1219a5c5b8e5bfdc1b6b10104736f6d658aa05647e0f89c231194d76e4f776ef7d3255028c484cb63a8a68f7d0251695ee27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000004e591f8d1dc5cd39185354241dcad64b66a8b68079855f815fcb7ca1fea8639ba00088df94402244351e7eee00409456665c6f6970ff1066e515f24938db8dfd633b40000000000000000fffffffffffffffff27e112e62134308df24f66cd6a133e473d72977d65f49467f1fd8a4d92a13c7010353746404426f6f6c03020566616c736500047472756501f41f2a6324dcada5162bb3034f7c2a19ad40b9124fb467e44c5a0d772c430d8e010353746405416c7068610334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7af5cacb7b3bfe2a23253ab1200a0bc7cdc84c72dd2b8b6a604f0705329bb2c5480008a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fe0000000000000000fffffffffffffffff82ac92fccaff7c18a77822734f7c200668e1cb198460b54211abc129a1b542c0107426974636f696e0b53637269707442797465730501a4423c76c2f6e30f76ec95d8e84eaf5dd4d61ae04c7dd66f3ff7bb3efec301fefd5e5e2b936f3d2e7a4cc4c25d577db7483e2dc4b92e962a18cb7833e676845d0107426974636f696e04566f75740501e27fe166fdfab25710d8a6c6a747c8981a74db00977347ef564945c189592531000000000191da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b00055247423231060f6174746163686d656e74547970657301869d8c797fddb35fefde3695c2df4eece5b76e39997b3ed27694fe7e835399f60001076372656174656401cad1bb9def7267a8f680452ce3634fe7814da5fa4be92ca71c5edf12e6a1e43001000a656e67726176696e677301497c7eb9391a079a38d92afdde2e4eec03a9a37987201d5ab5b14d45c17b250d0001047370656301b0ec0dee8fc4f8d16a12c28244458300356c728996760abdcecdfb163ddd89890100057465726d7301b0bfb6fe0093af6b3230e5fd0d3d69aaf14bf098df07728d250bae3779861070010006746f6b656e730106df6daab92b9b676ae2ad0833d22ddbd78e8f4ba127f9aff739b27d216db37c0001030a61737365744f776e6572055d514709a3b680d50475583bae26755d9f197784108c14897772d7cc5f4aa81000000112696e666c6174696f6e416c6c6f77616e636505c1f252f38965138fc5cb730e49eda0f7f792ed6b88b2e17739d6410d251b15140100010b75706461746552696768740101000000010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b7050f6174746163686d656e745479706573000000ffff0763726561746564000100010004737065630001000100057465726d73000100010006746f6b656e73000000ffff030a61737365744f776e6572000000ffff12696e666c6174696f6e416c6c6f77616e6365000000ffff0b757064617465526967687400000001000004010304090407456e67726176650100010a656e67726176696e67730001000100010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000401020708010b62656e656669636961727905497373756501010718363521c0c2e31915c8304a933e8f9c3e69d11ff99aaaa1499c61e98315b702126e65774174746163686d656e745479706573010f6174746163686d656e7454797065730000ffff096e6577546f6b656e730106746f6b656e730000ffff0104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff00050103040609010b62656e65666963696172790652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff0003010207010b62656e6566696369617279009048212cad2ed6e09a3e853c904f71889286e17ec23d0a3b6326ecee721b7b9901085472616e7366657200dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d491da3e27ebc8c7ff52366261a7d44068446d3cf62bd14b1d2381731fc5f3db9b0403000763726561746564340804737065633508057465726d73360806746f6b656e730134080b62656e656669636961727900013408085472616e7366657200000000dd6007ba4ee01c38948186659223dc7fa1772f66283014fdb1593444f59252d48000000403000100040000000000340801000c0004444942410444494241000235080100060004004449424136080100400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e6700000001340802010003011987f6bd6a50eefa39d9a9ba9ceed7400f6d264c7468f1dd48ed754bda17049701000000d8a350fa59d528fb0c000100000001000000000000000000000000000000000000000000"; +const UDA_CONTRACT: &str = "0100000000050300596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b0100340899624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100350818cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010036080b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb00174601003808086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c56840100013408021870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c05030001000100340801000100350801000100360800000100380800000100013408010001000000013408d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0001340801000100013408010001000056000001196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e870501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed707fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a5081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffffffffffffffff086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684060202696477f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f63046e616d65b6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf8205940b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3035f05737061636520046578636c210671756f7465732204686173682306646f6c6c6172240770657263656e742509616d70657273616e64260a61706f7374726f7068652708627261636b65744c2808627261636b6574522908617374657269736b2a04706c75732b05636f6d6d612c056d696e75732d03646f742e05736c6173682f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e653905636f6c6f6e3a0973656d69436f6c6f6e3b046c6573733c05657175616c3d07677265617465723e087175657374696f6e3f02617440014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a0a7371427261636b65744c5b096261636b536c6173685c0a7371427261636b6574525d0563617265745e066c6f646173685f086261636b7469636b60016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a0963427261636b65744c7b04706970657c0963427261636b6574527d0574696c64657e0b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb001746060805696e64657865015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d067469636b6572a1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e046e616d65cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a0764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e40138880770726576696577ae5d4de320882d36a046dd72848e756a08638149d751afac47a0b77d8c2733ac056d656469611b2fd8ca8d5f1671165441ae083116506c4e265a8d7cb9869a409db9701dafaa0b6174746163686d656e7473500a5e82892023b23d60a374fea4fd1f6b3bd66fec3f396fbe8aeac319dc9f8c0872657365727665736e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a3550ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0602047574786fe86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c5060570726f6f66f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed715dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465087a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed91140000000000000000ffffffffffffffff181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb1086015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f41010000000000000008000000000000001870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd59050265015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d19ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7718cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b010501560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515419ebe69d137048e1596fc1e7e950af0a64c1765f29e41224ab2d2bf4e7605c7705015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f1a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021b080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000014000000000000001b2fd8ca8d5f1671165441ae083116506c4e265a8d7cb9869a409db9701dafaa040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d652b9fd922298de5f15323ff775a1f79d0d35619fe1298ac9047ead0edf29fb66f1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904200401deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da8915900501e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e21e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac943750501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed72a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd071cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b659153022904220002b9fd922298de5f15323ff775a1f79d0d35619fe1298ac9047ead0edf29fb66f0501faa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c025122762d2519390702d9a3484b79e289e7bbf2a8cad7fb5d2bc0a5f8471dba6fa3c03c031a014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a30a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe7680807fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a50000000000000000ffffffffffffffff332de353e616da0cb6394a23d10773fae94ff131f4fe216b2d0001bff1c7b2fb06040776657273696f6ea87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e06696e7075747315dfa1833ae7a0256426366659a343d3ca0308da6670cfd663f19878ef9f7465076f7574707574738ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca086c6f636b54696d6535da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c339840868f9caa65acd0874d1a06eb2ee2614cdcd537f77615c836cb9a613d93033f04646173682d047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a35da1d1539206ebbdddca4c33d8731eaf29ba7da74df3dc882201c4e16b5b91c0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed73c8add893836f8c04c073d1f454d9525cf96a7d7557296fa663ddbaaefa843940334014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4050163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a406e55d3696e06af0b904b93f8a6b2baf00b19b278b2df825db46015395cda8f0501a4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72f45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b060108726573657276657347b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd47b3532053f83fc1ad3abe88453620cb647d86ce5ee4e3de56b5c938423eb9cd090ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd0000000000000000ffff000000000000500a5e82892023b23d60a374fea4fd1f6b3bd66fec3f396fbe8aeac319dc9f8c0a0001faa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c02512276000000000000000014000000000000005014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d4050184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f93915515408fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780000000000000000ffff000000000000596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f5be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269050107fc7e770beea38fc53848e2890f75b66935f005a2e954bd989f4c099392b0a55ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f00085d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f2203130b696e646976697369626c65000464656369010563656e746902056d696c6c690309646563694d696c6c69040a63656e74694d696c6c6905056d6963726f0609646563694d6963726f070a63656e74694d6963726f08046e616e6f0908646563694e616e6f0a0963656e74694e616e6f0b047069636f0c08646563695069636f0d0963656e74695069636f0e0566656d746f0f096465636946656d746f100a63656e746946656d746f11046174746f125f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8f05015014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d46015c0e70764a9f48ae71dd448caf4035bffebdb62eff70dc8794286f8910f410324047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a618622d17baef06602dfe775c980e0b36b6ebae8090d8075f7513bec4b93f64d03020566616c73650004747275650163aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a08fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da780100000000000000ff0000000000000065015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d0501a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed765eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a06020576616c756597f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b0c7363726970745075626b6579cae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea490436632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48f00446b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de0308106672616374696f6e4f766572666c6f77010e6e6f6e457175616c56616c756573020c696e76616c696450726f6f660314696e73756666696369656e7452657365727665730415697373756545786365656473416c6c6f77616e636506126e6f6e4672616374696f6e616c546f6b656e07126e6f6e456e6772617661626c65546f6b656e0815696e76616c69644174746163686d656e7454797065096e74cc9f1d0ccb54ceff2df324c9d455c1acea72323acdb75cce02b7bd97a355040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d657d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa24728ea68a97de7420f62a5969b04b872604bf45d6df38959c7e26e7a72490e4ad033f047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a066c6f646173685f016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7a77f0d07dccb3bb52a483de90c1e8528ea04e040c04178253411c821e21378f6300017a7b8f49025cafad1370f90a4b0bb78028c417521384c039b409386768ed911406040a707265764f7574707574e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50609736967536372697074cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec940873657175656e636501196d8529c8f6da444d154e8d9c8cbd9e0f8d89025a3bb09121c63d52b01e87077769746e657373ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb257d654e97ed96167c3c3c491357425127b6c0f008a2cd70541773fa1b2d4daa2405010ed21a3b1985f8f55f1affc7261d551f6bab4bf206cdc448fdcb97b7c44809cd8057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a50501181aa1e3ed74bd51a3ccdb6cb2180bd413f2f891c28a765f16a2a8f3ba2dabb184de03c07d1d477bb76d40a947d26e1ed87dc44eaf86720dd4dc8a48047373b3080b6c500d94264462fb71c0e87478037695b4646158b9ec519dd6d47e74dc54f3010000000000000028000000000000008ac60209af0af69c70a282f79ba38ddf4ab5a2afbca5da03dc69ffab00e395ca0865eb913c17e7e03d9bb1c615293b085ade1511a7ba1c6b30160a33722231a10a0000000000000000ffffffffffffffff97f5d70642ae2a3392253ba84e1dcec493e3bf3ed371b1877386354ecc88826b05015ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f99624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10602066e616d696e67de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff58609707265636973696f6e5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f229e14cce6b185cca477ba44634bfa2c5871a97e0c32b7aec1df6a94522a9319c70310025f3000025f3101025f3202025f3303025f3404025f3505025f3606025f3707025f3808025f3909035f31300a035f31310b035f31320c035f31330d035f31340e035f31350fa1f5ff46847f287b7b3063062ee4a342ed6334cf5e0fb2730d48cf7f5bb0037e040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46da38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655605012a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdda4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72f06020474797065fb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc69420464617461f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838a5cffb327513077e4f1fc96072928244a01ea18c6cdaf598da0b5735ac075ed70004a62e384a135184183b9da6b9796b06e88c75c6803139dd391148ea049ae3d7e10310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e6106656c6576656e62067477656c76656308746869727465656e6408666f75727465656e65076669667465656e66a7ccf154860d368a2b95e87ad394d13d7e6430ac493c7bcdbb95a1c5aea1ccb00602096170706c696564546f65015643e4488cf3f714340179d725e828f2c04bfc41cc3b27f6054fda37731d07636f6e74656e74a4c8bc8c13e5ed1abd6f635282aa70bbf77f4e3be571a6f9c7882c8a981ec72fa87cc6796467e557d744e5c9623ae00ccb95d91a0d2f03df74c075124fbec79e05016632da64bbf5bc3cc9f522452f5377a83804cdcd95006bc467a1394cc1a2b48fae5d4de320882d36a046dd72848e756a08638149d751afac47a0b77d8c2733ac040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d65406e55d3696e06af0b904b93f8a6b2baf00b19b278b2df825db46015395cda8fb6ebccff4b9f793259f04b314fb76612808a97c5285cb735ebe39ed8bf82059405011a13cfad8446fb15031758c2dfa6a09d583183eac1afa057e550d636a4e5021bbaa0e3fcab9d55d168bb1e26837153afe89f83a27e0498554d3963f6431fd3f4033e047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539014141014242014343014444014545014646014747014848014949014a4a014b4b014c4c014d4d014e4e014f4f015050015151015252015353015454015555015656015757015858015959015a5a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7abc2891b1c66ac5f5e61059a32077daa82333a1435bd34608b30b03fc017d9545030a047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e6539c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d651deddddb38b837060353fb361533ffa352f30397b4c7abc15bbdbd25da891590c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb32544866340360035f333220035f333321035f333422035f333523035f333624035f333725035f333826035f333927035f343028035f343129035f34322a035f34332b035f34342c035f34352d035f34362e035f34372f035f343830035f343931035f353032035f353133035f353234035f353335035f353436035f353537035f353638035f353739035f35383a035f35393b035f36303c035f36313d035f36323e035f36333f035f363440035f363541035f363642035f363743035f363844035f363945035f373046035f373147035f373248035f373349035f37344a035f37354b035f37364c035f37374d035f37384e035f37394f035f383050035f383151035f383252035f383353035f383454035f383555035f383656035f383757035f383858035f383959035f39305a035f39315b035f39325c035f39335d035f39345e035f39355f035f393660035f393761035f393862035f393963045f31303064045f31303165045f31303266045f31303367045f31303468045f31303569045f3130366a045f3130376b045f3130386c045f3130396d045f3131306e045f3131316f045f31313270045f31313371045f31313472045f31313573045f31313674045f31313775045f31313876045f31313977045f31323078045f31323179045f3132327a045f3132337b045f3132347c045f3132357d045f3132367e045f3132377fcae95645ac9ae8fb1892420d1c8b46c220aac64ce6dc8258866fa365aea4904305015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc705013f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4cbb261c09079bea5f78800d747feb5f8c024e2c04f73f945b468068df143ec9405015be69aabb827ae7a16a0c65f72ee867e327e63039aa8d51b176a5a1410b2e269cf8e262506a3a4b2a6abca385a6502abf8036046a6dd8da63ae61d309b3c752a040200046e6f6e65d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0104736f6d655f7ae1f33fc70d8ba4a8945811223ef9b35135ada0240f39b0dc282ee9e48b8fd83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c0000da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b408c3cad9212706689af885a1b06a8d27ed3d3ff250c409f93fee32eb325448663401000000000000004000000000000000de7c753c6bd56774f87245306ca463409710cee01bedca9120fcaeef93bff5860603067469636b65728057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5046e616d655014105f0c4026ca12abae377de26f8e3ca0608dd36c483ed70f47195cd334d40764657461696c7345b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0501da57a3e7de97d8c4dcaafbd143a882a7587e35c3fa805625098c97e71629a5b4e86a40cd5c25f9bde284ff69a51132a7412b2155bd0e5612c1bfe3849560c50606020474786964a38242f3cbd7d1d0a112da8de1602f56d4f86f0ec4c476c5c068594c4b04655604766f757421e33e43c5aa5cf2292753a338c167ed3b639c4dd9cebda98f346917bac94375e93845aac316b6d6d0642da28663d3f803a0767a405d73297b36be8bd911a46d05018057ae07f47b923accc5361fcf40d92982e841f757dd59b16d7bdbc8eabe99a5eedec3ebaa08fb010f2f96e17a0e039ad87fe60771a7301f8c5e88995d05676b0310047a65726f30036f6e65310374776f320574687265653304666f757234046669766535037369783605736576656e3705656967687438046e696e65390374656e4106656c6576656e42067477656c76654308746869727465656e4408666f75727465656e45076669667465656e46ef9b75968c7d8d6905f17c692061d6e93a2abe8248e6a70b0867a2dffe84fb25050130a0d30c6bbfe91e2490b34278c7bf7f66ee6444011888dc4132bf304c6fe768f2ba2480169e7d3a48fd00302d1fdf80b9e3118f01a25ba6752d7dcf81ef0838081cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b65915302290420000000000000000ffff000000000000f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1031a016161016262016363016464016565016666016767016868016969016a6a016b6b016c6c016d6d016e6e016f6f017070017171017272017373017474017575017676017777017878017979017a7afaa9838e0ae786f75e697467292235e328e14488d83fcddd79f3c33c0251227606020474797065086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c5684066469676573742a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebddfb6b2ec4700e9bf1cd0f24bb9ced0dd78dbb4e1dcaf5c68fa6935a7a4fdc694206030474797065e15eba16722843cc10954a1b33479dbc343c67693fb7ade855e17f656b9f583e0773756274797065c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298c0763686172736574c0ec009baa44e89cdbeb95c6f18117a53618352f070bc59fc1d8e49f07b4298cfba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78010000000001e6b0c7ab8033b92ebfff89bda3e3a4403a7c37454e4d1de2d78f7af8fe83008600055247423231060f6174746163686d656e74547970657301086754f41789c3b935123433d959aa4c5441190bc298e1c8d1a7ed92be8c56840001076372656174656401596e7a3a0ea3659e1030f18b4d65a3b913ee585007fcf75e0bb6cdc169c1c03b01000a656e67726176696e677301a7ccf154860d368a2b95e87ad394d13d7e6430ac493c7bcdbb95a1c5aea1ccb0000104737065630199624db7e426929954932edfc8d267a5529702293cd5abc0564e6f225b33faf10100057465726d730118cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01010006746f6b656e73010b8789e08890aa2ea1569dbbb6f547f9a435d30db8961fff85fba67deb0017460001030a61737365744f776e6572051870edcbec640794b304356cc55c909e7ffd3de152d84c73f2855e5783bbdd5900000112696e666c6174696f6e416c6c6f77616e636505140cb31d53f4bd9e48091b9b557d8203262f22c26ca7b1688652825b3f8ab23a0100010b7570646174655269676874010100000001467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b050f6174746163686d656e745479706573000000ffff0763726561746564000100010004737065630001000100057465726d73000100010006746f6b656e73000000ffff030a61737365744f776e6572000000ffff12696e666c6174696f6e416c6c6f77616e6365000000ffff0b757064617465526967687400000001000004010304090407456e67726176650100010a656e67726176696e67730001000100010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff000401020708010b62656e65666963696172790549737375650101467bac8139b1f513fd37b31e74459d860ab2f67033da9ad472e6da3d1ff38a7b02126e65774174746163686d656e745479706573010f6174746163686d656e7454797065730000ffff096e6577546f6b656e730106746f6b656e730000ffff0104757365640112696e666c6174696f6e416c6c6f77616e63650100ffff020b62656e6566696369617279010a61737365744f776e65720000ffff066675747572650112696e666c6174696f6e416c6c6f77616e63650000ffff00050103040609010b62656e65666963696172790652656e616d65010001036e657701047370656301000100010475736564010b7570646174655269676874010001000106667574757265010b75706461746552696768740000010000000106667574757265085472616e73666572000000010870726576696f7573010a61737365744f776e65720100ffff010b62656e6566696369617279010a61737365744f776e65720100ffff0003010207010b62656e6566696369617279006b87cc20476a4daa93590b2568db9e0ed54ab8c43c8e938bb72f4e1ad7f1e9de01085472616e7366657200ca0c967f8bb57d6d85c8a0d0e1ac58816aa9a8d503bb279c50d8e37655f94c73e6b0c7ab8033b92ebfff89bda3e3a4403a7c37454e4d1de2d78f7af8fe8300860403000763726561746564340804737065633508057465726d73360806746f6b656e730134080b62656e656669636961727900013408085472616e7366657200000000ca0c967f8bb57d6d85c8a0d0e1ac58816aa9a8d503bb279c50d8e37655f94c738000000403000100040000000000340801000c0004444942410444494241000235080100060004004449424136080100400001000000010444494241010444494241000105696d6167650103706e67001d0068747470733a2f2f636172626f6e61646f2e696f2f646962612e706e6700000001340802010003019ee7b29502b09271f6e1f7222fdb5c276d4df6c2b4cd4e33ff960e21e353ae9401000000b4d3d37e2fe0bbb40c000100000001000000000000000000000000000000000000000000"; From 1103d2eaddf7ba5b2172717325e34cf83ba20993 Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Mon, 26 Jun 2023 23:51:34 -0300 Subject: [PATCH 03/27] feat: allow build psbt with multiple inputs --- src/rgb.rs | 31 +- src/rgb/psbt.rs | 138 ++++--- src/structs.rs | 17 +- tests/rgb/integration/fungibles.rs | 3 +- tests/rgb/integration/states.rs | 6 +- tests/rgb/integration/stress.rs | 10 +- tests/rgb/integration/transfers.rs | 619 ++++++++++++++++++++++++++++- tests/rgb/integration/udas.rs | 3 +- tests/rgb/integration/utils.rs | 25 +- tests/rgb/unit/psbt.rs | 8 +- 10 files changed, 733 insertions(+), 127 deletions(-) diff --git a/src/rgb.rs b/src/rgb.rs index 8cfbba37..8387d1c4 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -1,4 +1,4 @@ -use std::str::FromStr; +use std::{collections::BTreeMap, str::FromStr}; use ::psbt::serialize::Serialize; use amplify::{confinement::U16, hex::ToHex}; @@ -187,12 +187,10 @@ pub async fn create_invoice(sk: &str, request: InvoiceRequest) -> Result Result { let PsbtRequest { descriptor_pub, - asset_utxo, - asset_utxo_terminal, - change_index, + inputs, bitcoin_changes, + change_index, fee, - tapret, } = request; let stock = retrieve_stock(sk, ASSETS_STOCK).await?; @@ -203,31 +201,40 @@ pub async fn create_psbt(sk: &str, request: PsbtRequest) -> Result explorer_url: BITCOIN_EXPLORER_API.read().await.to_string(), ..Default::default() }; - prefetch_resolver_psbt(&asset_utxo, &mut resolver).await; + for asset_utxo in inputs.clone() { + prefetch_resolver_psbt(&asset_utxo.asset_utxo, &mut resolver).await; + } + let bitcoin_inputs: BTreeMap = inputs + .clone() + .into_iter() + .map(|input| (input.asset_utxo, input.asset_utxo_terminal)) + .collect(); // Retrieve transaction fee let fee = match fee { Some(fee) => fee, _ => estimate_fee_tx( &descriptor_pub, - &asset_utxo, - &asset_utxo_terminal, - change_index, + bitcoin_inputs, bitcoin_changes.clone(), + change_index, &mut resolver, ), }; + let asset_inputs: Vec<(String, String, Option)> = inputs + .into_iter() + .map(|input| (input.asset_utxo, input.asset_utxo_terminal, input.tapret)) + .collect(); + let wallet = rgb_account.wallets.get("default"); let (psbt_file, change_terminal) = create_rgb_psbt( descriptor_pub.0.to_string(), - asset_utxo, - asset_utxo_terminal.clone(), + asset_inputs, change_index, bitcoin_changes, fee, wallet.cloned(), - tapret, &resolver, )?; diff --git a/src/rgb/psbt.rs b/src/rgb/psbt.rs index c62e017c..42c2dc81 100644 --- a/src/rgb/psbt.rs +++ b/src/rgb/psbt.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeMap; use std::str::FromStr; use amplify::hex::ToHex; @@ -6,7 +7,7 @@ use bdk::FeeRate; use bitcoin::secp256k1::SECP256K1; use bitcoin::util::bip32::Fingerprint; use bitcoin::{EcdsaSighashType, OutPoint, Script, XOnlyPublicKey}; -// TODO: Incompletible versions between RGB and Descriptor Wallet +// TODO: Incompatible versions between RGB and Descriptor Wallet use bitcoin_30::secp256k1::SECP256K1 as SECP256K1_30; use bitcoin_30::taproot::TaprootBuilder; use bitcoin_30::ScriptBuf; @@ -40,25 +41,59 @@ use crate::structs::SecretString; #[allow(clippy::too_many_arguments)] pub fn create_psbt( descriptor_pub: String, - asset_utxo: String, - asset_utxo_terminal: String, - change_index: Option, + asset_utxos: Vec<(String, String, Option)>, + bitcoin_change_index: Option, bitcoin_changes: Vec, - fee: u64, + bitcoin_fee: u64, wallet: Option, - tapret: Option, tx_resolver: &impl ResolveTx, ) -> Result<(Psbt, String), ProprietaryKeyError> { - let outpoint: OutPoint = asset_utxo.parse().expect("invalid outpoint parse"); - let mut input = InputDescriptor { - outpoint, - terminal: asset_utxo_terminal - .parse() - .expect("invalid terminal path parse"), - seq_no: SeqNo::default(), - tweak: None, - sighash_type: EcdsaSighashType::All, - }; + let mut inputs = vec![]; + + // Define Descriptor + let (_, terminal, _) = asset_utxos.first().unwrap(); + let terminal: DerivationSubpath = + terminal.parse().expect("invalid terminal path parse"); + + let contract_index = terminal.first().expect("first derivation index"); + let terminal_step = format!("/{contract_index}/*"); + + let descriptor_pub = descriptor_pub.replace(&terminal_step, "/*/*"); + let descriptor: &Descriptor = + &Descriptor::from_str(&descriptor_pub).expect("invalid descriptor parse"); + + // Define Input Descriptors + for (asset_utxo, asset_utxo_terminal, tapret) in asset_utxos { + let outpoint: OutPoint = asset_utxo.parse().expect("invalid outpoint parse"); + let mut input = InputDescriptor { + outpoint, + terminal: asset_utxo_terminal + .parse() + .expect("invalid terminal path parse"), + seq_no: SeqNo::default(), + tweak: None, + sighash_type: EcdsaSighashType::All, + }; + + // Verify TapTweak (User Input or Watcher inspect) + if let Some(tapret) = tapret { + input.tweak = Some(( + Fingerprint::default(), + tapret.parse().expect("invalid hash"), + )) + } else if let Some(tweak) = complete_input_desc( + descriptor.clone(), + input.clone(), + wallet.clone(), + tx_resolver, + ) + .expect("complete descriptor error") + { + input.tweak = Some((Fingerprint::default(), tweak.parse().expect("invalid hash"))) + } + + inputs.push(input); + } let bitcoin_addresses: Vec = bitcoin_changes .into_iter() @@ -70,14 +105,7 @@ pub fn create_psbt( .map(|AddressAmount { address, amount }| (address.script_pubkey().into(), amount)) .collect(); - // to avoid derivation mismatched - let contract_index = input.terminal.first().expect("first derivation index"); - let terminal_step = format!("/{contract_index}/*"); - - let descriptor_pub = descriptor_pub.replace(&terminal_step, "/*/*"); - let descriptor: &Descriptor = - &Descriptor::from_str(&descriptor_pub).expect("invalid descriptor parse"); - + // Define Tapret Proprierties let proprietary_keys = vec![ProprietaryKeyDescriptor { location: ProprietaryKeyLocation::Output(0_u16), ty: ProprietaryKeyType { @@ -89,8 +117,8 @@ pub fn create_psbt( }]; // Change Terminal Derivation - let mut change_derivation = vec![input.terminal[0]]; - let change_index = match change_index { + let mut change_derivation = vec![terminal[0]]; + let change_index = match bitcoin_change_index { Some(index) => { UnhardenedIndex::from_str(&index.to_string()).expect("invalid change_index parse") } @@ -99,27 +127,12 @@ pub fn create_psbt( change_derivation.insert(1, change_index); let change_terminal = format!("/{contract_index}/{change_index}"); - // Verify TapTweak (User Input) - if let Some(tapret) = tapret { - input.tweak = Some(( - Fingerprint::default(), - tapret.parse().expect("invalid hash"), - )) - } - // Verify TapTweak (Watcher inspect) - else if let Some(tweak) = - complete_input_desc(descriptor.clone(), input.clone(), wallet, tx_resolver).expect("") - { - input.tweak = Some((Fingerprint::default(), tweak.parse().expect("invalid hash"))) - } - - let inputs = vec![input]; let mut psbt = Psbt::construct( descriptor, &inputs, &outputs, change_derivation, - fee, + bitcoin_fee, tx_resolver, ) .expect("cannot be construct PSBT information"); @@ -214,7 +227,7 @@ fn complete_input_desc( .add_leaf(0, tap_tweak) .expect("complete tree"); - // TODO: Incompletible versions between RGB and Descriptor Wallet + // TODO: Incompatible versions between RGB and Descriptor Wallet let xonly_30 = bitcoin_30::secp256k1::XOnlyPublicKey::from_str(&xonly.to_hex()) .expect(""); @@ -290,25 +303,27 @@ pub fn save_commit(terminal: &str, commit: Vec, wallet: &mut RgbWallet) { // TODO: [Experimental] Review with Diba Team pub fn estimate_fee_tx( descriptor_pub: &SecretString, - asset_utxo: &str, - asset_utxo_terminal: &str, - asset_change_index: Option, + bitcoin_inputs: BTreeMap, bitcoin_changes: Vec, + bitcoin_change_index: Option, resolver: &mut T, ) -> u64 where T: ResolveTx + Resolver, { - let outpoint = OutPoint::from_str(asset_utxo).expect("invalid outpoint"); - let asset_change_index = match asset_change_index { - Some(index) => index.into(), - _ => UnhardenedIndex::default(), - }; - let mut vout_value = 0; - if let Ok(tx) = resolver.resolve_tx(outpoint.txid) { - if let Some(vout) = tx.output.to_vec().get(outpoint.vout as usize) { - vout_value = vout.value; + let mut bitcoin_terminal = String::new(); + + for (utxo, terminal) in bitcoin_inputs { + let outpoint = OutPoint::from_str(&utxo).expect("invalid outpoint"); + if let Ok(tx) = resolver.resolve_tx(outpoint.txid) { + if let Some(vout) = tx.output.to_vec().get(outpoint.vout as usize) { + vout_value = vout.value; + } + + if bitcoin_terminal.is_empty() { + bitcoin_terminal = terminal; + } } } @@ -320,10 +335,15 @@ where total_spent += recipient.amount; } + let bitcoin_change_index = match bitcoin_change_index { + Some(index) => index.into(), + _ => UnhardenedIndex::default(), + }; + // Main Recipient total_spent = vout_value - total_spent; let target_script = - get_recipient_script(descriptor_pub, asset_utxo_terminal, asset_change_index) + get_recipient_script(descriptor_pub, &bitcoin_terminal, bitcoin_change_index) .expect("invalid derivation"); // TODO: Provide way to get fee rate estimate @@ -341,14 +361,14 @@ where fn get_recipient_script( descriptor_pub: &SecretString, - asset_utxo_terminal: &str, + bitcoin_terminal: &str, change_index: UnhardenedIndex, ) -> Option