diff --git a/.env b/.env new file mode 100644 index 0000000..92ae4c2 --- /dev/null +++ b/.env @@ -0,0 +1,21 @@ +# RPC NAME AND PASSWORD +RPC_USER=bitcoin +RPC_PASSWORD=bitcoin +# Bitcoin Core RPC Port +BITCOIN_RPC_PORT_1=18443 +BITCOIN_RPC_PORT_2=18444 +BITCOIN_RPC_PORT_3=18445 +# Electrum RPC Port +ELECTRUM_PORT_1=50001 +ELECTRUM_PORT_2=50002 +ELECTRUM_PORT_3=50003 +# Electrs HTTP API Port +API_PORT_1=3001 +API_PORT_2=3002 +API_PORT_3=3003 +# Esplora UI Port +EXPLORE_UI_PORT_1=5005 +EXPLORE_UI_PORT_2=5006 +EXPLORE_UI_PORT_3=5007 + + diff --git a/.gitmodules b/.gitmodules index 7b781f5..b9ef25b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,6 @@ [submodule "rust-aluvm"] path = rust-aluvm url = https://github.com/aluvm/rust-aluvm -[submodule "rgb-interfaces"] - path = rgb-interfaces - url = https://github.com/RGB-WG/rgb-interfaces [submodule "client_side_validation"] path = client_side_validation url = https://github.com/LNP-BP/client_side_validation/ @@ -19,9 +16,6 @@ [submodule "bp-std"] path = bp-std url = https://github.com/BP-WG/bp-std -[submodule "rgb-schemata"] - path = rgb-schemata - url = https://github.com/RGB-WG/rgb-schemata [submodule "strict-types"] path = strict-types url = https://github.com/strict-types/strict-types @@ -39,16 +33,13 @@ url = https://github.com/RGB-WG/rgb [submodule "bp-wallet"] path = bp-wallet - url = https://github.com/BP-WG/bp-wallet + url = https://github.com/BP-WG/bp-wallet.git [submodule "amplify-num"] path = amplify-num url = https://github.com/rust-amplify/amplify-num.git [submodule "amplify-derive"] path = amplify-derive url = https://github.com/rust-amplify/amplify-derive.git -[submodule "ascii-armor"] - path = ascii-armor - url = https://github.com/UBIDECO/ascii-armor.git [submodule "bp-esplora-client"] path = bp-esplora-client url = https://github.com/BP-WG/bp-esplora-client.git @@ -61,3 +52,15 @@ [submodule "amplify-nonasync"] path = amplify-nonasync url = https://github.com/rust-amplify/amplify-nonasync.git +[submodule "zk-aluvm"] + path = zk-aluvm + url = https://github.com/AluVM/zk-aluvm +[submodule "ultrasonic"] + path = ultrasonic + url = https://github.com/AluVM/ultrasonic +[submodule "sonic"] + path = sonic + url = https://github.com/AluVM/sonic.git +[submodule "rgb-interfaces"] + path = rgb-interfaces + url = https://github.com/RGB-WG/rgb-interfaces.git diff --git a/Cargo.lock b/Cargo.lock index 923c3be..1f8330f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" @@ -28,47 +28,34 @@ dependencies = [ [[package]] name = "aluvm" -version = "0.11.0-beta.9" +version = "0.12.0-rc.1" dependencies = [ "amplify", - "ascii-armor", "baid64", - "blake3", - "getrandom", - "half", + "commit_verify", + "getrandom 0.2.16", + "getrandom 0.3.3", "paste", - "ripemd", "serde", - "sha2", "strict_encoding", - "strict_types", "wasm-bindgen", ] [[package]] name = "amplify" -version = "4.7.0" +version = "4.9.0" dependencies = [ - "amplify_apfloat", "amplify_derive", "amplify_num", "amplify_syn", "ascii", - "rand", + "getrandom 0.2.16", + "getrandom 0.3.3", "serde", "stringly_conversions", "wasm-bindgen", ] -[[package]] -name = "amplify_apfloat" -version = "0.3.1" -dependencies = [ - "amplify_num", - "bitflags 2.5.0", - "wasm-bindgen", -] - [[package]] name = "amplify_derive" version = "4.0.1" @@ -112,16 +99,24 @@ dependencies = [ ] [[package]] -name = "arrayref" -version = "0.3.7" +name = "aora" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "fa0b56f69d2c47f8ee387f40849742d552e8b94596d997c19095809ac5c6b377" +dependencies = [ + "amplify", + "binfile", + "getrandom 0.2.16", + "indexmap 2.9.0", + "strict_encoding", + "wasm-bindgen", +] [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii" @@ -134,7 +129,9 @@ dependencies = [ [[package]] name = "ascii-armor" -version = "0.7.2" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0269eb842ec952b027df0fc33184b6a0dea5ea473160b36992274eb53758461e" dependencies = [ "amplify", "baid64", @@ -145,55 +142,53 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-lc-rs" -version = "1.7.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7d844e282b4b56750b2d4e893b2205581ded8709fddd2b6aa5418c150ca877" +checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" dependencies = [ "aws-lc-sys", - "mirai-annotations", - "paste", "zeroize", ] [[package]] name = "aws-lc-sys" -version = "0.18.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a2c29203f6bf296d01141cc8bb9dbd5ecd4c27843f2ee0767bcd5985a927da" +checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" dependencies = [ "bindgen", "cc", "cmake", "dunce", "fs_extra", - "libc", - "paste", ] [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] name = "baid64" -version = "0.2.2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61eced31ae690ea39ffe808ed970bd11ebbb3ccc6861d2ab787d848b03a0d049" dependencies = [ "amplify", "base64", @@ -224,11 +219,11 @@ checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] name = "bindgen" -version = "0.69.4" +version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.5.0", + "bitflags", "cexpr", "clang-sys", "itertools", @@ -241,21 +236,24 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.66", + "syn 2.0.102", "which", ] [[package]] -name = "bitcoin-io" -version = "0.1.2" +name = "binfile" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" +checksum = "6274ba7d40c4296332ddf908383673f96412b853337a4df0f6ecc9495ec5ff7d" +dependencies = [ + "amplify", +] [[package]] -name = "bitcoin-private" -version = "0.1.0" +name = "bitcoin-io" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" [[package]] name = "bitcoin_hashes" @@ -269,28 +267,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "blake3" -version = "1.5.4" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", -] +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "block-buffer" @@ -301,69 +280,79 @@ dependencies = [ "generic-array", ] +[[package]] +name = "borrow-or-share" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" + [[package]] name = "bp-consensus" -version = "0.11.0-beta.9" +version = "0.12.0-rc.2" dependencies = [ "amplify", "chrono", "commit_verify", - "secp256k1 0.30.0", + "getrandom 0.2.16", + "getrandom 0.3.3", + "secp256k1", "serde", "strict_encoding", "strict_types", + "wasm-bindgen", ] [[package]] name = "bp-core" -version = "0.11.0-beta.9" +version = "0.12.0-rc.2" dependencies = [ - "amplify", "bp-consensus", "bp-dbc", "bp-seals", "commit_verify", - "getrandom", + "getrandom 0.2.16", + "getrandom 0.3.3", "serde", - "single_use_seals", "strict_encoding", - "strict_types", "wasm-bindgen", ] [[package]] name = "bp-dbc" -version = "0.11.0-beta.9" +version = "0.12.0-rc.2" dependencies = [ "amplify", "base85", "bp-consensus", "commit_verify", - "secp256k1 0.30.0", + "getrandom 0.2.16", + "getrandom 0.3.3", + "secp256k1", "serde", "strict_encoding", + "wasm-bindgen", ] [[package]] name = "bp-derive" -version = "0.11.0-beta.9.1" +version = "0.12.0-rc.2" dependencies = [ "amplify", "bp-consensus", "bp-invoice", "commit_verify", "hmac", - "indexmap 2.6.0", + "indexmap 2.9.0", "serde", "sha2", ] [[package]] name = "bp-electrum" -version = "0.11.0-beta.9.3" +version = "0.12.0-rc.1" dependencies = [ "amplify", - "bp-std", + "bp-core", "byteorder", "libc", "log", @@ -371,53 +360,57 @@ dependencies = [ "serde", "serde_json", "sha2", - "webpki-roots", + "webpki-roots 0.26.11", "winapi", ] [[package]] name = "bp-esplora" -version = "0.11.0-beta.9" +version = "0.12.0-rc.1" dependencies = [ "amplify", - "bp-std", + "bp-core", + "bp-invoice", "log", + "minreq", "reqwest", "serde", - "serde_with", + "serde_with 3.12.0", "sha2", - "ureq", + "tokio", ] [[package]] name = "bp-invoice" -version = "0.11.0-beta.9.1" +version = "0.12.0-rc.2" dependencies = [ "amplify", "bech32", "bp-consensus", "commit_verify", "serde", + "strict_encoding", ] [[package]] name = "bp-seals" -version = "0.11.0-beta.9" +version = "0.12.0-rc.2" dependencies = [ "amplify", - "baid64", "bp-consensus", "bp-dbc", "commit_verify", - "rand", + "getrandom 0.2.16", + "getrandom 0.3.3", "serde", "single_use_seals", "strict_encoding", + "wasm-bindgen", ] [[package]] name = "bp-std" -version = "0.11.0-beta.9.1" +version = "0.12.0-rc.2" dependencies = [ "amplify", "bp-consensus", @@ -425,23 +418,25 @@ dependencies = [ "bp-derive", "bp-invoice", "descriptors", - "getrandom", + "getrandom 0.2.16", + "getrandom 0.3.3", "psbt", - "secp256k1 0.30.0", + "secp256k1", "serde", "wasm-bindgen", ] [[package]] name = "bp-wallet" -version = "0.11.0-beta.9.1" +version = "0.12.0-rc.2" dependencies = [ "amplify", "bp-electrum", "bp-esplora", "bp-std", "descriptors", - "log", + "getrandom 0.2.16", + "getrandom 0.3.3", "nonasync", "psbt", "serde", @@ -450,13 +445,20 @@ dependencies = [ "sha2", "strict_encoding", "toml", + "wasm-bindgen", ] [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" + +[[package]] +name = "bytecount" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "byteorder" @@ -466,15 +468,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.1.18" +version = "1.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" dependencies = [ "jobserver", "libc", @@ -492,15 +494,15 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -508,7 +510,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -524,16 +526,16 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.50" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ "cc", ] [[package]] name = "commit_encoding_derive" -version = "0.11.0-beta.9" +version = "0.12.0-rc.1" dependencies = [ "amplify", "amplify_syn", @@ -544,25 +546,22 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.11.0-beta.9" +version = "0.12.0-rc.1" dependencies = [ "amplify", "commit_encoding_derive", - "rand", + "getrandom 0.2.16", + "getrandom 0.3.3", + "rand 0.9.1", "ripemd", "serde", "sha2", "strict_encoding", "strict_types", "vesper-lang", + "wasm-bindgen", ] -[[package]] -name = "constant_time_eq" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" - [[package]] name = "core-foundation" version = "0.9.4" @@ -575,84 +574,104 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] -name = "crc32fast" -version = "1.4.0" +name = "crypto-common" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "cfg-if", + "generic-array", + "typenum", ] [[package]] -name = "crunchy" -version = "0.2.2" +name = "darling" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", +] [[package]] -name = "crypto-common" -version = "0.1.6" +name = "darling" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "generic-array", - "typenum", + "darling_core 0.20.11", + "darling_macro 0.20.11", ] [[package]] -name = "darling" -version = "0.20.8" +name = "darling_core" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ - "darling_core", - "darling_macro", + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", ] [[package]] name = "darling_core" -version = "0.20.8" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim", - "syn 2.0.66", + "strsim 0.11.1", + "syn 2.0.102", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn 1.0.109", ] [[package]] name = "darling_macro" -version = "0.20.8" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core", + "darling_core 0.20.11", "quote", - "syn 2.0.66", + "syn 2.0.102", ] [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", "serde", @@ -660,11 +679,11 @@ dependencies = [ [[package]] name = "descriptors" -version = "0.11.0-beta.9.1" +version = "0.12.0-rc.2" dependencies = [ "amplify", "bp-derive", - "indexmap 2.6.0", + "indexmap 2.9.0", "serde", ] @@ -679,45 +698,50 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.102", +] + [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "either" -version = "1.11.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] -[[package]] -name = "fast32" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35a73237400bde66c82e38387343f90d7182a2f2f22729e096a2abd57d75db9" - [[package]] name = "fastrand" -version = "2.0.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "file-format" @@ -725,23 +749,14 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ffe3a660c3a1b10e96f304a9413d673b2118d62e4520f7ddf4a4faccfe8b9b9" -[[package]] -name = "flate2" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fluent-uri" -version = "0.1.4" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" +checksum = "1918b65d96df47d3591bed19c5cca17e3fa5d0707318e4b5ef2eae01764df7e5" dependencies = [ - "bitflags 1.3.2", + "borrow-or-share", + "ref-cast", ] [[package]] @@ -782,9 +797,9 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -797,9 +812,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -807,15 +822,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -824,32 +839,32 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.102", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -859,9 +874,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -887,38 +902,42 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] [[package]] -name = "gimli" -version = "0.28.1" +name = "getrandom" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", +] [[package]] -name = "glob" -version = "0.3.1" +name = "gimli" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] -name = "half" -version = "2.4.1" +name = "glob" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "hashbrown" @@ -928,15 +947,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" [[package]] name = "heck" @@ -970,18 +983,18 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "http" -version = "1.1.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -990,9 +1003,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", @@ -1000,12 +1013,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", + "futures-core", "http", "http-body", "pin-project-lite", @@ -1013,15 +1026,15 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "hyper" -version = "1.3.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", @@ -1054,34 +1067,59 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.5" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ + "base64", "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] +[[package]] +name = "hypersonic" +version = "0.12.0-rc.2" +dependencies = [ + "aluvm", + "amplify", + "binfile", + "commit_verify", + "getrandom 0.2.16", + "getrandom 0.3.3", + "indexmap 2.9.0", + "serde", + "sonic-api", + "sonic-callreq", + "strict_encoding", + "strict_types", + "ultrasonic", + "wasm-bindgen", +] + [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -1095,6 +1133,92 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1103,12 +1227,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1124,20 +1259,30 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.4", "serde", ] [[package]] name = "ipnet" -version = "2.9.0" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] [[package]] name = "itertools" @@ -1150,33 +1295,35 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lazycell" @@ -1186,31 +1333,43 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.0", ] [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -1218,21 +1377,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "mime" -version = "0.3.17" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "minimal-lexical" @@ -1242,29 +1395,35 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", ] [[package]] -name = "mio" -version = "0.8.11" +name = "minreq" +version = "2.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "f0d2aaba477837b46ec1289588180fabfccf0c3b1d1a0c6b1866240cd6cd5ce9" dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", + "base64", + "log", + "serde", + "serde_json", ] [[package]] -name = "mirai-annotations" -version = "1.12.0" +name = "mio" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] [[package]] name = "mnemonic" @@ -1274,11 +1433,10 @@ checksum = "f2b8f3a258db515d5e91a904ce4ae3f73e091149b90cadbdb93d210bee07f63b" [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -1302,10 +1460,9 @@ dependencies = [ [[package]] name = "nonasync" -version = "0.1.2" +version = "0.1.3" dependencies = [ "amplify", - "log", ] [[package]] @@ -1316,35 +1473,35 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "object" -version = "0.32.2" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.5.0", + "bitflags", "cfg-if", "foreign-types", "libc", @@ -1361,20 +1518,20 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.102", ] [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -1382,11 +1539,22 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "papergrid" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b915f831b85d984193fdc3d3611505871dc139b2534530fa01c1a6a6707b6723" +dependencies = [ + "bytecount", + "fnv", + "unicode-width", +] + [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -1394,9 +1562,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -1407,9 +1575,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "percent-encoding" @@ -1417,31 +1585,11 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1451,9 +1599,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] [[package]] name = "powerfmt" @@ -1463,54 +1620,84 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "prettyplease" -version = "0.2.20" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" +dependencies = [ + "proc-macro2", + "syn 2.0.102", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ + "proc-macro-error-attr2", "proc-macro2", - "syn 2.0.66", + "quote", + "syn 2.0.102", ] [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "psbt" -version = "0.11.0-beta.9.1" +version = "0.12.0-rc.2" dependencies = [ "amplify", "base64", "bp-core", "bp-derive", - "chrono", "commit_verify", "descriptors", - "indexmap 2.6.0", + "indexmap 2.9.0", "serde", "strict_encoding", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rand" version = "0.8.5" @@ -1518,8 +1705,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -1529,7 +1726,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -1538,23 +1745,52 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", ] [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ - "bitflags 2.5.0", + "proc-macro2", + "quote", + "syn 2.0.102", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -1564,9 +1800,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1575,9 +1811,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relative-path" @@ -1587,76 +1823,67 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" dependencies = [ "base64", "bytes", "futures-core", - "futures-util", "http", "http-body", "http-body-util", "hyper", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", - "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", "tokio-native-tls", - "tokio-socks", + "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows-registry", ] [[package]] name = "rgb-core" -version = "0.11.0-beta.9" +version = "0.12.0-rc.2" dependencies = [ - "aluvm", "amplify", - "baid64", "bp-core", - "chrono", "commit_verify", - "getrandom", - "mime", - "secp256k1-zkp", + "getrandom 0.2.16", + "getrandom 0.3.3", "serde", "single_use_seals", "strict_encoding", - "strict_types", + "ultrasonic", "wasm-bindgen", ] [[package]] name = "rgb-interfaces" -version = "0.11.0-beta.9" +version = "0.12.0-rc.2" dependencies = [ - "aluvm", "amplify", - "bp-core", - "chrono", - "getrandom", - "rgb-std", - "serde_json", - "sha2", + "bp-consensus", + "commit_verify", + "getrandom 0.2.16", + "getrandom 0.3.3", + "serde", + "serde_with 1.14.0", "strict_encoding", "strict_types", "wasm-bindgen", @@ -1664,54 +1891,55 @@ dependencies = [ [[package]] name = "rgb-invoice" -version = "0.11.0-beta.9.1" +version = "0.12.0-rc.2" dependencies = [ "amplify", "baid64", "bp-core", "bp-invoice", - "fast32", - "fluent-uri", - "indexmap 2.6.0", - "percent-encoding", - "rand", + "commit_verify", + "hypersonic", "rgb-core", "serde", + "sonic-callreq", + "strict_encoding", +] + +[[package]] +name = "rgb-persist-fs" +version = "0.12.0-rc.2" +dependencies = [ + "amplify", + "aora", + "rgb-std", + "sonic-persist-fs", "strict_encoding", - "strict_types", ] [[package]] name = "rgb-psbt" -version = "0.11.0-beta.9" +version = "0.12.0-rc.2" dependencies = [ "amplify", - "baid64", "bp-core", "bp-std", - "commit_verify", - "getrandom", "rgb-std", - "strict_encoding", - "wasm-bindgen", ] [[package]] name = "rgb-runtime" -version = "0.11.0-beta.9" +version = "0.12.0-rc.2" dependencies = [ "amplify", - "baid64", - "bp-core", - "bp-electrum", - "bp-esplora", "bp-std", "bp-wallet", "chrono", "commit_verify", - "getrandom", - "indexmap 2.6.0", + "getrandom 0.2.16", + "getrandom 0.3.3", + "indexmap 2.9.0", "nonasync", + "rgb-persist-fs", "rgb-psbt", "rgb-std", "serde", @@ -1720,42 +1948,26 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "rgb-schemata" -version = "0.11.0-beta.9" -dependencies = [ - "aluvm", - "amplify", - "bp-core", - "chrono", - "rgb-interfaces", - "rgb-std", - "serde", - "serde_json", - "sha2", - "strict_encoding", - "strict_types", -] - [[package]] name = "rgb-std" -version = "0.11.0-beta.9.1" +version = "0.12.0-rc.2" dependencies = [ - "aluvm", "amplify", - "ascii-armor", - "baid64", - "base85", + "aora", + "binfile", "bp-core", + "bp-invoice", "chrono", "commit_verify", - "getrandom", - "indexmap 2.6.0", - "nonasync", - "rand", + "getrandom 0.2.16", + "getrandom 0.3.3", + "hypersonic", + "indexmap 2.9.0", "rgb-core", "rgb-invoice", "serde", + "serde_with 1.14.0", + "single_use_seals", "strict_encoding", "strict_types", "wasm-bindgen", @@ -1766,6 +1978,7 @@ name = "rgb-tests" version = "0.1.0" dependencies = [ "amplify", + "amplify_derive", "bitcoin_hashes", "bp-core", "bp-electrum", @@ -1773,38 +1986,45 @@ dependencies = [ "bp-invoice", "bp-std", "bp-wallet", + "commit_verify", "descriptors", "file-format", + "hypersonic", + "indexmap 2.9.0", "once_cell", "psbt", - "rand", + "rand 0.8.5", "rgb-interfaces", + "rgb-persist-fs", "rgb-psbt", "rgb-runtime", - "rgb-schemata", "rgb-std", "rstest", "rstest_reuse", + "serde", + "serde_json", "serde_yaml", "serial_test", + "single_use_seals", + "sonic-persist-fs", "strict_encoding", "strict_types", "strum", "strum_macros", + "tabled", "time", ] [[package]] name = "ring" -version = "0.17.8" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.16", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -1843,7 +2063,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.66", + "syn 2.0.102", "unicode-ident", ] @@ -1854,16 +2074,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88530b681abe67924d42cca181d070e3ac20e0740569441a9e35a7cedd2b34a4" dependencies = [ "quote", - "rand", + "rand 0.8.5", "rustc_version", - "syn 2.0.66", + "syn 2.0.102", ] [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -1873,36 +2093,48 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.5.0", + "bitflags", "errno", "libc", - "linux-raw-sys", - "windows-sys 0.52.0", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.7" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebbbdb961df0ad3f2652da8f3fdc4b36122f568f968f45ad3316f26c025c677b" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "aws-lc-rs", "log", "once_cell", - "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -1910,26 +2142,19 @@ dependencies = [ ] [[package]] -name = "rustls-pemfile" -version = "2.1.2" +name = "rustls-pki-types" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ - "base64", - "rustls-pki-types", + "zeroize", ] -[[package]] -name = "rustls-pki-types" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" - [[package]] name = "rustls-webpki" -version = "0.102.3" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "aws-lc-rs", "ring", @@ -1939,32 +2164,32 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "scc" -version = "2.2.6" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b13f8ea6177672c49d12ed964cca44836f59621981b04a3e26b87e675181de" +checksum = "22b2d775fb28f245817589471dd49c5edf64237f4a19d10ce9a92ff4651a27f4" dependencies = [ "sdd", ] [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1975,20 +2200,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sdd" -version = "3.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478f121bb72bbf63c52c93011ea1791dca40140dfe13f8336c4c5ac952c33aa9" - -[[package]] -name = "secp256k1" -version = "0.29.0" +version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" -dependencies = [ - "rand", - "secp256k1-sys", - "serde", -] +checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" [[package]] name = "secp256k1" @@ -1997,50 +2211,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", - "rand", + "rand 0.8.5", "secp256k1-sys", "serde", ] [[package]] name = "secp256k1-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" -dependencies = [ - "cc", -] - -[[package]] -name = "secp256k1-zkp" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a44aed3002b5ae975f8624c5df3a949cfbf00479e18778b6058fcd213b76e3" -dependencies = [ - "bitcoin-private", - "rand", - "secp256k1 0.29.0", - "secp256k1-zkp-sys", - "serde", -] - -[[package]] -name = "secp256k1-zkp-sys" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6eea7919e0cab992510edfbf40bd9342c0a3c2bb910f2c51355c2cb2d69839" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", - "secp256k1-sys", ] [[package]] name = "security-framework" -version = "2.10.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -2049,9 +2240,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.10.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -2059,46 +2250,47 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.198" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.102", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -2127,32 +2319,54 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.11.0" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros 1.5.2", +] + +[[package]] +name = "serde_with" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "base64", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.6.0", + "indexmap 2.9.0", "serde", "serde_derive", "serde_json", - "serde_with_macros", + "serde_with_macros 3.12.0", "time", ] [[package]] name = "serde_with_macros" -version = "3.11.0" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling 0.13.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_with_macros" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ - "darling", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.102", ] [[package]] @@ -2161,7 +2375,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.9.0", "itoa", "ryu", "serde", @@ -2190,14 +2404,14 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.102", ] [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -2212,9 +2426,10 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" -version = "0.11.0-beta.9" +version = "0.12.0-rc.1" dependencies = [ - "amplify_derive", + "serde", + "strict_encoding", ] [[package]] @@ -2228,43 +2443,87 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] -name = "socks" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b" +name = "sonic-api" +version = "0.12.0-rc.2" dependencies = [ - "byteorder", - "libc", - "winapi", + "aluvm", + "amplify", + "baid64", + "binfile", + "chrono", + "commit_verify", + "getrandom 0.2.16", + "getrandom 0.3.3", + "indexmap 2.9.0", + "serde", + "serde_yaml", + "sonic-callreq", + "strict_encoding", + "strict_types", + "ultrasonic", + "wasm-bindgen", +] + +[[package]] +name = "sonic-callreq" +version = "0.12.0-rc.2" +dependencies = [ + "amplify", + "baid64", + "chrono", + "fluent-uri", + "getrandom 0.2.16", + "getrandom 0.3.3", + "indexmap 2.9.0", + "serde", + "strict_encoding", + "strict_types", + "ultrasonic", + "wasm-bindgen", +] + +[[package]] +name = "sonic-persist-fs" +version = "0.12.0-rc.2" +dependencies = [ + "amplify", + "aora", + "binfile", + "commit_verify", + "hypersonic", + "serde_yaml", + "strict_encoding", + "toml", ] [[package]] -name = "spin" -version = "0.9.8" +name = "stable_deref_trait" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "strict_encoding" -version = "2.7.0" +version = "2.9.1" dependencies = [ "amplify", - "half", + "getrandom 0.2.16", + "getrandom 0.3.3", "serde", "strict_encoding_derive", "wasm-bindgen", @@ -2272,10 +2531,10 @@ dependencies = [ [[package]] name = "strict_encoding_derive" -version = "2.7.0" +version = "2.9.1" dependencies = [ "amplify_syn", - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 1.0.109", @@ -2283,13 +2542,14 @@ dependencies = [ [[package]] name = "strict_types" -version = "2.7.2" +version = "2.9.0" dependencies = [ "amplify", "ascii-armor", "baid64", - "half", - "indexmap 2.6.0", + "getrandom 0.2.16", + "getrandom 0.3.3", + "indexmap 2.9.0", "serde", "serde_json", "serde_yaml", @@ -2316,33 +2576,39 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.66", + "syn 2.0.102", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2357,9 +2623,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" dependencies = [ "proc-macro2", "quote", @@ -2368,50 +2634,85 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.102", +] + +[[package]] +name = "tabled" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121d8171ee5687a4978d1b244f7d99c43e7385a272185a2f1e1fa4dc0979d444" +dependencies = [ + "papergrid", + "tabled_derive", +] + +[[package]] +name = "tabled_derive" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52d9946811baad81710ec921809e2af67ad77719418673b2a3794932d57b7538" +dependencies = [ + "heck", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.102", +] + [[package]] name = "tempfile" -version = "3.10.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand", - "rustix", - "windows-sys 0.52.0", + "getrandom 0.3.3", + "once_cell", + "rustix 1.0.7", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.102", ] [[package]] name = "time" -version = "0.3.36" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -2424,40 +2725,35 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "tinystr" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" -version = "1.37.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -2465,7 +2761,7 @@ dependencies = [ "mio", "pin-project-lite", "socket2", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2478,23 +2774,11 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-socks" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" -dependencies = [ - "either", - "futures-util", - "thiserror", - "tokio", -] - [[package]] name = "toml" -version = "0.8.19" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -2504,58 +2788,83 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tower" -version = "0.4.13" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "pin-project", "pin-project-lite", + "sync_wrapper", "tokio", "tower-layer", "tower-service", ] +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-core", @@ -2563,9 +2872,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", ] @@ -2578,30 +2887,36 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +name = "ultrasonic" +version = "0.12.0-rc.2" +dependencies = [ + "amplify", + "baid64", + "commit_verify", + "getrandom 0.2.16", + "getrandom 0.3.3", + "serde", + "strict_encoding", + "wasm-bindgen", + "zk-aluvm", +] [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] -name = "unicode-normalization" -version = "0.1.23" +name = "unicode-width" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" [[package]] name = "unsafe-libyaml" @@ -2615,36 +2930,23 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "ureq" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" -dependencies = [ - "base64", - "flate2", - "log", - "once_cell", - "rustls", - "rustls-pki-types", - "serde", - "serde_json", - "socks", - "url", - "webpki-roots", -] - [[package]] name = "url" -version = "2.5.0" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "vcpkg" version = "0.2.15" @@ -2653,13 +2955,15 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vesper-lang" -version = "0.1.0" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd2b7e3e27aeb0524204e58042f6e4531a720745d1b1a3978d3a084f1885f63d" dependencies = [ "amplify", "strict_encoding", @@ -2676,52 +2980,63 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.102", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2729,28 +3044,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.102", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -2758,9 +3076,18 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.1" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.0", +] + +[[package]] +name = "webpki-roots" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" dependencies = [ "rustls-pki-types", ] @@ -2774,7 +3101,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix", + "rustix 0.38.44", ] [[package]] @@ -2801,50 +3128,61 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-registry" -version = "0.2.0" +name = "windows-implement" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ - "windows-result", - "windows-strings", - "windows-targets 0.52.6", + "proc-macro2", + "quote", + "syn 2.0.102", ] [[package]] -name = "windows-result" -version = "0.2.0" +name = "windows-interface" +version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ - "windows-targets 0.52.6", + "proc-macro2", + "quote", + "syn 2.0.102", ] [[package]] -name = "windows-strings" -version = "0.1.0" +name = "windows-link" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-result", - "windows-targets 0.52.6", + "windows-link", ] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "windows-strings" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-targets 0.48.5", + "windows-link", ] [[package]] @@ -2857,18 +3195,12 @@ dependencies = [ ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -2880,7 +3212,7 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", @@ -2888,10 +3220,20 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" +name = "windows-targets" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] [[package]] name = "windows_aarch64_gnullvm" @@ -2900,10 +3242,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +name = "windows_aarch64_gnullvm" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" @@ -2912,10 +3254,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "windows_i686_gnu" -version = "0.48.5" +name = "windows_aarch64_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" @@ -2923,6 +3265,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" @@ -2930,10 +3278,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] -name = "windows_i686_msvc" -version = "0.48.5" +name = "windows_i686_gnullvm" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] name = "windows_i686_msvc" @@ -2942,10 +3290,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" +name = "windows_i686_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" @@ -2954,10 +3302,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +name = "windows_x86_64_gnu" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] name = "windows_x86_64_gnullvm" @@ -2966,10 +3314,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +name = "windows_x86_64_gnullvm" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" @@ -2977,31 +3325,153 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" -version = "0.6.18" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.102", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.102", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.102", + "synstructure", +] + [[package]] name = "zeroize" -version = "1.8.0" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63381fa6624bf92130a6b87c0d07380116f80b565c42cf0d754136f0238359ef" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" dependencies = [ - "zeroize_derive", + "displaydoc", + "yoke", + "zerofrom", ] [[package]] -name = "zeroize_derive" -version = "1.4.2" +name = "zerovec" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.102", ] + +[[package]] +name = "zk-aluvm" +version = "0.12.0-rc.2" +dependencies = [ + "aluvm", + "amplify", + "getrandom 0.2.16", + "getrandom 0.3.3", + "serde", + "strict_encoding", + "wasm-bindgen", +] + +[[patch.unused]] +name = "baid64" +version = "0.4.1" diff --git a/Cargo.toml b/Cargo.toml index 7140ef0..0a64e46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,11 +20,14 @@ once_cell = "1.19.0" rand = "0.8.5" rstest = "0.19.0" rstest_reuse = "0.6.0" +serde = "1.0.215" serde_yaml = "0.9" +serde_json = "1.0" serial_test = "3.2.0" strum = { version = "0.26.2", features = ["derive"] } strum_macros = "0.26.2" -time = "0.3.34" +time = { version = "0.3.34", features = ["formatting"] } +indexmap = "2.7.0" # RGB-related deps ## bp-core @@ -46,37 +49,46 @@ bp-wallet = { path = "./bp-wallet", features = [ ] } ## rgb rgb-runtime = { path = "./rgb", features = [ - "electrum_blocking", - "esplora_blocking", + # "electrum_blocking", + # "esplora_blocking", "fs", "serde", ] } -rgb-psbt = { path = "./rgb/psbt" } -## rgb-interfaces -rgb-interfaces = { path = "./rgb-interfaces" } -## rgb-schemata -rgb-schemata = { path = "./rgb-schemata" } +rgb-psbt = { path = "./rgb/psbt", features = ["bp"] } ## rgb-std -rgb-std = { path = "./rgb-std", features = ["fs"] } +rgb-std = { path = "./rgb-std", features = ["binfile"] } +rgb-persist-fs = { path = "./rgb-std/persistence/fs" } +## rgb-interfaces +rgb-interfaces = { path = "./rgb-interfaces", features = ["serde"] } ## rust-amplify amplify = { path = "./rust-amplify" } +amplify_derive = { path = "./amplify-derive" } ## strict-encoding -strict_encoding = { path = "./strict-encoding/rust" } +strict_encoding = { path = "./strict-encoding/rust", features = ["serde"] } ## strict-types strict_types = { path = "./strict-types" } +## commit_verify +commit_verify = { path = "./client_side_validation/commit_verify" } +## sonic +hypersonic = { path = "./sonic" } +sonic-persist-fs = { path = "./sonic/persistence/fs" } +## single_use_seals +single_use_seals = { path = "./client_side_validation/single_use_seals", features = ["strict_encoding"] } +tabled = "0.18.0" + + [patch.crates-io] # patching all RGB-related deps, to measure code coverage +## rust-amplify +amplify = { path = "./rust-amplify" } ## amplify-derive amplify_derive = { path = "./amplify-derive" } amplify_syn = { path = "./amplify-derive/syn" } ## amplify-nonasync nonasync = { path = "./amplify-nonasync" } ## amplify-num -amplify_apfloat = { path = "./amplify-num/apfloat" } amplify_num = { path = "./amplify-num/num" } -## ascii-armor -ascii-armor = { path = "./ascii-armor" } ## baid64 baid64 = { path = "./rust-baid64" } ## bp-core @@ -105,21 +117,23 @@ rgb-runtime = { path = "./rgb" } rgb-psbt = { path = "./rgb/psbt" } ## rgb-core rgb-core = { path = "./rgb-core" } -## rgb-interfaces -rgb-interfaces = { path = "./rgb-interfaces" } -## rgb-schemata -rgb-schemata = { path = "./rgb-schemata" } ## rgb-std -rgb-std = { path = "./rgb-std" } rgb-invoice = { path = "./rgb-std/invoice" } +rgb-std = { path = "./rgb-std" } +rgb-persist-fs = { path = "./rgb-std/persistence/fs" } +## rgb-interfaces +rgb-interfaces = { path = "./rgb-interfaces" } ## rust-aluvm aluvm = { path = "./rust-aluvm" } -## rust-amplify -amplify = { path = "./rust-amplify" } +zk-aluvm = { path = "./zk-aluvm" } +## SONIC +ultrasonic = { path = "./ultrasonic" } +sonic-api = { path = "./sonic/api" } +sonic-callreq = { path = "./sonic/callreq" } +hypersonic = { path = "./sonic" } +sonic-persist-fs = { path = "./sonic/persistence/fs" } ## strict-encoding strict_encoding = { path = "./strict-encoding/rust" } strict_encoding_derive = { path = "./strict-encoding/rust/derive" } ## strict-types strict_types = { path = "./strict-types" } -## vesper -vesper-lang = { path = "./vesper" } diff --git a/amplify-nonasync b/amplify-nonasync index 1a5ecbf..9f4f586 160000 --- a/amplify-nonasync +++ b/amplify-nonasync @@ -1 +1 @@ -Subproject commit 1a5ecbf8d9eb8616cf0c091ceee6ff2fcc941780 +Subproject commit 9f4f5861d0fe314c2928a3e0f516f69c7377c2d3 diff --git a/amplify-num b/amplify-num index be035c1..98cda24 160000 --- a/amplify-num +++ b/amplify-num @@ -1 +1 @@ -Subproject commit be035c1ed260313217bd799bd47cbc9bdfdf27ec +Subproject commit 98cda24f2ed2d19ffaba743f59f9ad34464bb492 diff --git a/ascii-armor b/ascii-armor deleted file mode 160000 index 3d8b4cb..0000000 --- a/ascii-armor +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3d8b4cb5a20c6ec5ec41fae4d88f3f0004917072 diff --git a/bp-core b/bp-core index a928721..0967b34 160000 --- a/bp-core +++ b/bp-core @@ -1 +1 @@ -Subproject commit a9287214102c70be45f05dec1aba3decb62d3173 +Subproject commit 0967b34cbfe43bf8a79ac963e3a96589a1cc49b1 diff --git a/bp-electrum-client b/bp-electrum-client index a660268..150fa03 160000 --- a/bp-electrum-client +++ b/bp-electrum-client @@ -1 +1 @@ -Subproject commit a66026874b948479b14aa5f01629c677ae005abc +Subproject commit 150fa0343b116e39b44530743afdb7a64a0aa3d9 diff --git a/bp-esplora-client b/bp-esplora-client index 87e487e..8313e0e 160000 --- a/bp-esplora-client +++ b/bp-esplora-client @@ -1 +1 @@ -Subproject commit 87e487e1aa8547833253f951929769a646e9387f +Subproject commit 8313e0eda770d67e1552d72afb2ae30ca766431b diff --git a/bp-std b/bp-std index f81848a..e6ee238 160000 --- a/bp-std +++ b/bp-std @@ -1 +1 @@ -Subproject commit f81848a0751e073c92881c2d6c9c06c87e7a58bd +Subproject commit e6ee238ad1be3982bb41e3193ccf10acb42e7fbc diff --git a/bp-wallet b/bp-wallet index 429c853..346eadd 160000 --- a/bp-wallet +++ b/bp-wallet @@ -1 +1 @@ -Subproject commit 429c853ad424d0d4e08b6b496b35fe8a4b64a321 +Subproject commit 346eadd1c3c5f41813f05387903082d9a457803f diff --git a/client_side_validation b/client_side_validation index 7215fb5..8d34606 160000 --- a/client_side_validation +++ b/client_side_validation @@ -1 +1 @@ -Subproject commit 7215fb50a7ef56f090a051dffe23a3c318bb8351 +Subproject commit 8d3460691469b0c7e9fbbf863ff54e1047618dc9 diff --git a/reports/rgb_asset_issuance_test_report.md b/reports/rgb_asset_issuance_test_report.md new file mode 100644 index 0000000..46dda37 --- /dev/null +++ b/reports/rgb_asset_issuance_test_report.md @@ -0,0 +1,45 @@ +# RGB Asset Issuance Test Report + +## Overview + +This test report covers the issuance functionality of different asset types in the RGB protocol, including RGB20 (NIA), RGB25 (FUA), and RGB21 (FAC) assets. + +## Test Environment +- Testing Framework: Rust Test +- Test File: `tests/issuance.rs` +- Test Cases: 10 test cases covering different asset types and wallet types + +## Test Results Summary + +### Successful Cases (8/10) + +1. **RGB20 - NIA Assets** + - Single UTXO issuance tests (`issue_nia::case_1`, `issue_nia::case_2`) + - Multiple UTXO issuance tests (`issue_nia_multiple_utxos::case_1`, `issue_nia_multiple_utxos::case_2`) + - Support for both Wpkh and Tr wallet types + +2. **RGB25 - FUA Assets** + - Single UTXO issuance tests (`issue_fua::case_1`, `issue_fua::case_2`) + - Multiple UTXO issuance tests (`issue_fua_multiple_utxos::case_1`, `issue_fua_multiple_utxos::case_2`) + - Support for both Wpkh and Tr wallet types + +### Failed Cases (2/10) + +**RGB21 - FAC Assets** +- Test cases: `issue_fac::case_1`, `issue_fac::case_2` +- Context: + Despite completing the adaptation for the latest RGB21 asset structure, we still encountered issuance failures during testing +- Error message: + ``` + failed to issue contract: Inner(Genesis(Named(TypeName("DigitalCollection")), ScriptUnspecified)) + ``` +- Failure analysis: + We suspect that the `FN_ASSET_SPEC` validation script implementation is incompatible with the RGB21 asset structure, causing validation failures. We respectfully request the Doctor's judgment on whether different validation logic needs to be created for RGB21 assets. + +## Next Steps + +1. Current focus is on stability and performance testing of RGB20 assets +2. RGB21-related issues are merely being collected for future solutions from the Doctor +3. Collect and synchronize feedback on RGB21 asset issuance problems + +*Note: RGB21 is not our main focus at this stage, as we are currently concentrating on improving the functionality of RGB20.* \ No newline at end of file diff --git a/rgb b/rgb index 55a814a..3d23d04 160000 --- a/rgb +++ b/rgb @@ -1 +1 @@ -Subproject commit 55a814a6ff37677934e764790e4e0b31a5d0f18b +Subproject commit 3d23d04e30adc8f4ad8ff055e787e12197e0ec0e diff --git a/rgb-core b/rgb-core index 52592c6..e7ca10d 160000 --- a/rgb-core +++ b/rgb-core @@ -1 +1 @@ -Subproject commit 52592c62f9f0ba32b3deab69725f2fd6cd6784c4 +Subproject commit e7ca10d858271309d32f06527ba9e0aaf9595689 diff --git a/rgb-interfaces b/rgb-interfaces index 70b5528..5070fd3 160000 --- a/rgb-interfaces +++ b/rgb-interfaces @@ -1 +1 @@ -Subproject commit 70b5528cb2b93dae57796373fd9ef81506cae352 +Subproject commit 5070fd31574975564d00a73107e011c927319fc2 diff --git a/rgb-schemata b/rgb-schemata deleted file mode 160000 index 7a66a9b..0000000 --- a/rgb-schemata +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7a66a9b02a3a36d3f121cbc5833fe876caf9f1f2 diff --git a/rgb-std b/rgb-std index b374468..78393b5 160000 --- a/rgb-std +++ b/rgb-std @@ -1 +1 @@ -Subproject commit b3744689e7ff2603b7093afdea09db50d032c5ca +Subproject commit 78393b5821a0bf5e80e02cae7090dae53c39d685 diff --git a/rust-aluvm b/rust-aluvm index b671b88..b72e543 160000 --- a/rust-aluvm +++ b/rust-aluvm @@ -1 +1 @@ -Subproject commit b671b8803c0b843881c017c759d7c0dc1ef816ea +Subproject commit b72e543d4373036965323775b6113e05a0b43bef diff --git a/rust-amplify b/rust-amplify index d01b9f5..97e49a3 160000 --- a/rust-amplify +++ b/rust-amplify @@ -1 +1 @@ -Subproject commit d01b9f52c23e839c6620f68d1bf9099152178f6d +Subproject commit 97e49a3e8716ab2990a55d65475cf6d409395432 diff --git a/rust-baid64 b/rust-baid64 index 983854a..aaa426f 160000 --- a/rust-baid64 +++ b/rust-baid64 @@ -1 +1 @@ -Subproject commit 983854a1b9be7c2cd7d98b00ab4df3e633be393a +Subproject commit aaa426fd30f812c5ff07cd72d4ddc61b74b9bc4e diff --git a/sonic b/sonic new file mode 160000 index 0000000..8ff532b --- /dev/null +++ b/sonic @@ -0,0 +1 @@ +Subproject commit 8ff532b84f38fa85ca7c6da859eabcbd42e807a0 diff --git a/strict-encoding b/strict-encoding index b11845c..c32aa6c 160000 --- a/strict-encoding +++ b/strict-encoding @@ -1 +1 @@ -Subproject commit b11845c2d811d87c69a597b6602914141ca31227 +Subproject commit c32aa6c3d850663941ad9782ab50445593d3e4ea diff --git a/strict-types b/strict-types index b353f5d..3b101ec 160000 --- a/strict-types +++ b/strict-types @@ -1 +1 @@ -Subproject commit b353f5dbc0076dae918ac14175d347a3cc1aad0c +Subproject commit 3b101ec7c91cfac45c8b9feff01540dd5f593f64 diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml deleted file mode 100644 index 037f580..0000000 --- a/tests/docker-compose.yml +++ /dev/null @@ -1,76 +0,0 @@ -services: - bitcoind_1: - image: registry.gitlab.com/hashbeam/docker/bitcoind:25.0 - profiles: [electrum] - command: "-fallbackfee=0.0002" - bitcoind_2: - image: registry.gitlab.com/hashbeam/docker/bitcoind:25.0 - profiles: [electrum] - command: "-fallbackfee=0.0002" - bitcoind_3: - image: registry.gitlab.com/hashbeam/docker/bitcoind:25.0 - profiles: [electrum] - command: "-fallbackfee=0.0002" - electrs_1: - image: registry.gitlab.com/hashbeam/docker/electrs:0.9.14 - profiles: [electrum] - environment: - BTCHOST: bitcoind_1 - ports: - - 50001:50001 - depends_on: - - bitcoind_1 - electrs_2: - image: registry.gitlab.com/hashbeam/docker/electrs:0.9.14 - profiles: [electrum] - environment: - BTCHOST: bitcoind_2 - ports: - - 50002:50001 - depends_on: - - bitcoind_2 - electrs_3: - image: registry.gitlab.com/hashbeam/docker/electrs:0.9.14 - profiles: [electrum] - environment: - BTCHOST: bitcoind_3 - ports: - - 50003:50001 - depends_on: - - bitcoind_3 - esplora_1: - image: blockstream/esplora:956c74f42eb6ad803d8aedc272ba83d3aa6dcf5c - profiles: [esplora] - command: /srv/explorer/run.sh bitcoin-regtest explorer - environment: - DEBUG: verbose - NO_PRECACHE: 1 - NO_ADDRESS_SEARCH: 1 - NO_REGTEST_MINING: 1 - ports: - - 50004:50001 - - 8094:80 - esplora_2: - image: blockstream/esplora:956c74f42eb6ad803d8aedc272ba83d3aa6dcf5c - profiles: [esplora] - command: /srv/explorer/run.sh bitcoin-regtest explorer - environment: - DEBUG: verbose - NO_PRECACHE: 1 - NO_ADDRESS_SEARCH: 1 - NO_REGTEST_MINING: 1 - ports: - - 50005:50001 - - 8095:80 - esplora_3: - image: blockstream/esplora:956c74f42eb6ad803d8aedc272ba83d3aa6dcf5c - profiles: [esplora] - command: /srv/explorer/run.sh bitcoin-regtest explorer - environment: - DEBUG: verbose - NO_PRECACHE: 1 - NO_ADDRESS_SEARCH: 1 - NO_REGTEST_MINING: 1 - ports: - - 50006:50001 - - 8096:80 diff --git a/tests/docker/.env b/tests/docker/.env new file mode 100644 index 0000000..92ae4c2 --- /dev/null +++ b/tests/docker/.env @@ -0,0 +1,21 @@ +# RPC NAME AND PASSWORD +RPC_USER=bitcoin +RPC_PASSWORD=bitcoin +# Bitcoin Core RPC Port +BITCOIN_RPC_PORT_1=18443 +BITCOIN_RPC_PORT_2=18444 +BITCOIN_RPC_PORT_3=18445 +# Electrum RPC Port +ELECTRUM_PORT_1=50001 +ELECTRUM_PORT_2=50002 +ELECTRUM_PORT_3=50003 +# Electrs HTTP API Port +API_PORT_1=3001 +API_PORT_2=3002 +API_PORT_3=3003 +# Esplora UI Port +EXPLORE_UI_PORT_1=5005 +EXPLORE_UI_PORT_2=5006 +EXPLORE_UI_PORT_3=5007 + + diff --git a/tests/docker/docker-compose.yml b/tests/docker/docker-compose.yml new file mode 100644 index 0000000..c37cdee --- /dev/null +++ b/tests/docker/docker-compose.yml @@ -0,0 +1,308 @@ +# Project name: rgb-tests +# Use with: docker compose -p rgb-tests +volumes: + bitcoin-data-1: + bitcoin-data-2: + bitcoin-data-3: + +networks: + rgb-tests-1: + driver: bridge + ipam: + config: + - subnet: 172.30.1.0/24 + rgb-tests-2: + driver: bridge + ipam: + config: + - subnet: 172.30.2.0/24 + +services: + # Node 1 services (isolated network) + init-1: + container_name: bitcoin-init-1 + networks: + - rgb-tests-1 + image: bitlightlabs/bitcoind:v27.0 + restart: "no" + entrypoint: /bin/sh + volumes: + - bitcoin-data-1:/data/.bitcoin + command: + - -c + - | + echo "Initializing bitcoind configuration for node 1" + echo "# Global settings" > /data/.bitcoin/bitcoin.conf + echo "server=1" >> /data/.bitcoin/bitcoin.conf + echo "discover=0" >> /data/.bitcoin/bitcoin.conf + echo "dns=0" >> /data/.bitcoin/bitcoin.conf + echo "dnsseed=0" >> /data/.bitcoin/bitcoin.conf + echo "upnp=0" >> /data/.bitcoin/bitcoin.conf + echo "natpmp=0" >> /data/.bitcoin/bitcoin.conf + echo "rpcuser=${RPC_USER}" >> /data/.bitcoin/bitcoin.conf + echo "rpcpassword=${RPC_PASSWORD}" >> /data/.bitcoin/bitcoin.conf + echo "rpcallowip=0.0.0.0/0" >> /data/.bitcoin/bitcoin.conf + echo "changetype=bech32" >> /data/.bitcoin/bitcoin.conf + echo "fallbackfee=0.0002" >> /data/.bitcoin/bitcoin.conf + echo "zmqpubrawblock=tcp://0.0.0.0:28332" >> /data/.bitcoin/bitcoin.conf + echo "zmqpubrawtx=tcp://0.0.0.0:28333" >> /data/.bitcoin/bitcoin.conf + echo "txindex=1" >> /data/.bitcoin/bitcoin.conf + echo "" >> /data/.bitcoin/bitcoin.conf + echo "# Regtest settings" >> /data/.bitcoin/bitcoin.conf + echo "[regtest]" >> /data/.bitcoin/bitcoin.conf + echo "regtest=1" >> /data/.bitcoin/bitcoin.conf + echo "listen=1" >> /data/.bitcoin/bitcoin.conf + echo "bind=0.0.0.0" >> /data/.bitcoin/bitcoin.conf + echo "port=18444" >> /data/.bitcoin/bitcoin.conf + echo "rpcbind=0.0.0.0" >> /data/.bitcoin/bitcoin.conf + echo "rpcport=18443" >> /data/.bitcoin/bitcoin.conf + echo "taproot=1" >> /data/.bitcoin/bitcoin.conf + + bitcoin-core-1: + container_name: bitcoin-core-1 + networks: + rgb-tests-1: + ipv4_address: 172.30.1.205 + image: bitlightlabs/bitcoind:v27.0 + restart: on-failure + depends_on: + - init-1 + volumes: + - bitcoin-data-1:/data/.bitcoin + entrypoint: /bin/sh + ports: + - "${BITCOIN_RPC_PORT_1:-18443}:18443" + command: + - -c + - | + while [ ! -f /data/.bitcoin/bitcoin.conf ]; do sleep 1; done + bitcoind -regtest -rpcbind=0.0.0.0 -listenonion=0 + + esplora-api-1: + container_name: esplora-api-1 + networks: + - rgb-tests-1 + image: bitlightlabs/esplora-api:latest + volumes: + - bitcoin-data-1:/data/.bitcoin + depends_on: + - bitcoin-core-1 + command: + - -vvvv + - --network + - regtest + - --daemon-dir + - /data/.bitcoin + - --daemon-rpc-addr + - 172.30.1.205:18443 + - --cors + - "*" + - --cookie + - "${RPC_USER:-bitcoin}:${RPC_PASSWORD:-bitcoin}" + - --http-addr + - "0.0.0.0:3000" + - --electrum-rpc-addr + - 0.0.0.0:50001 + ports: + - "${ELECTRUM_PORT_1:-50001}:50001" + - "${API_PORT_1:-3001}:3000" + + # Node 2 & 3 services (shared network) + init-2: + container_name: bitcoin-init-2 + networks: + - rgb-tests-2 + image: bitlightlabs/bitcoind:v27.0 + restart: "no" + entrypoint: /bin/sh + volumes: + - bitcoin-data-2:/data/.bitcoin + command: + - -c + - | + echo "Initializing bitcoind configuration for node 2" + echo "# Global settings" > /data/.bitcoin/bitcoin.conf + echo "server=1" >> /data/.bitcoin/bitcoin.conf + echo "discover=0" >> /data/.bitcoin/bitcoin.conf + echo "dns=0" >> /data/.bitcoin/bitcoin.conf + echo "dnsseed=0" >> /data/.bitcoin/bitcoin.conf + echo "upnp=0" >> /data/.bitcoin/bitcoin.conf + echo "natpmp=0" >> /data/.bitcoin/bitcoin.conf + echo "rpcuser=${RPC_USER}" >> /data/.bitcoin/bitcoin.conf + echo "rpcpassword=${RPC_PASSWORD}" >> /data/.bitcoin/bitcoin.conf + echo "rpcallowip=0.0.0.0/0" >> /data/.bitcoin/bitcoin.conf + echo "changetype=bech32" >> /data/.bitcoin/bitcoin.conf + echo "fallbackfee=0.0002" >> /data/.bitcoin/bitcoin.conf + echo "zmqpubrawblock=tcp://0.0.0.0:28332" >> /data/.bitcoin/bitcoin.conf + echo "zmqpubrawtx=tcp://0.0.0.0:28333" >> /data/.bitcoin/bitcoin.conf + echo "txindex=1" >> /data/.bitcoin/bitcoin.conf + echo "" >> /data/.bitcoin/bitcoin.conf + echo "# Regtest settings" >> /data/.bitcoin/bitcoin.conf + echo "[regtest]" >> /data/.bitcoin/bitcoin.conf + echo "regtest=1" >> /data/.bitcoin/bitcoin.conf + echo "listen=1" >> /data/.bitcoin/bitcoin.conf + echo "bind=0.0.0.0" >> /data/.bitcoin/bitcoin.conf + echo "port=18444" >> /data/.bitcoin/bitcoin.conf + echo "rpcbind=0.0.0.0" >> /data/.bitcoin/bitcoin.conf + echo "rpcport=18443" >> /data/.bitcoin/bitcoin.conf + echo "taproot=1" >> /data/.bitcoin/bitcoin.conf + + init-3: + container_name: bitcoin-init-3 + networks: + - rgb-tests-2 + image: bitlightlabs/bitcoind:v27.0 + restart: "no" + entrypoint: /bin/sh + volumes: + - bitcoin-data-3:/data/.bitcoin + command: + - -c + - | + echo "Initializing bitcoind configuration for node 3" + echo "# Global settings" > /data/.bitcoin/bitcoin.conf + echo "server=1" >> /data/.bitcoin/bitcoin.conf + echo "discover=0" >> /data/.bitcoin/bitcoin.conf + echo "dns=0" >> /data/.bitcoin/bitcoin.conf + echo "dnsseed=0" >> /data/.bitcoin/bitcoin.conf + echo "upnp=0" >> /data/.bitcoin/bitcoin.conf + echo "natpmp=0" >> /data/.bitcoin/bitcoin.conf + echo "rpcuser=${RPC_USER}" >> /data/.bitcoin/bitcoin.conf + echo "rpcpassword=${RPC_PASSWORD}" >> /data/.bitcoin/bitcoin.conf + echo "rpcallowip=0.0.0.0/0" >> /data/.bitcoin/bitcoin.conf + echo "changetype=bech32" >> /data/.bitcoin/bitcoin.conf + echo "fallbackfee=0.0002" >> /data/.bitcoin/bitcoin.conf + echo "zmqpubrawblock=tcp://0.0.0.0:28332" >> /data/.bitcoin/bitcoin.conf + echo "zmqpubrawtx=tcp://0.0.0.0:28333" >> /data/.bitcoin/bitcoin.conf + echo "txindex=1" >> /data/.bitcoin/bitcoin.conf + echo "" >> /data/.bitcoin/bitcoin.conf + echo "# Regtest settings" >> /data/.bitcoin/bitcoin.conf + echo "[regtest]" >> /data/.bitcoin/bitcoin.conf + echo "regtest=1" >> /data/.bitcoin/bitcoin.conf + echo "listen=1" >> /data/.bitcoin/bitcoin.conf + echo "bind=0.0.0.0" >> /data/.bitcoin/bitcoin.conf + echo "port=18444" >> /data/.bitcoin/bitcoin.conf + echo "rpcbind=0.0.0.0" >> /data/.bitcoin/bitcoin.conf + echo "rpcport=18443" >> /data/.bitcoin/bitcoin.conf + echo "taproot=1" >> /data/.bitcoin/bitcoin.conf + + bitcoin-core-2: + container_name: bitcoin-core-2 + networks: + rgb-tests-2: + ipv4_address: 172.30.2.205 + image: bitlightlabs/bitcoind:v27.0 + restart: on-failure + depends_on: + - init-2 + volumes: + - bitcoin-data-2:/data/.bitcoin + entrypoint: /bin/sh + ports: + - "${BITCOIN_RPC_PORT_2:-18444}:18443" + - "28444:18444" + command: + - -c + - | + while [ ! -f /data/.bitcoin/bitcoin.conf ]; do sleep 1; done + bitcoind -regtest -rpcbind=0.0.0.0 -listenonion=0 -discover=0 -dns=0 + + bitcoin-core-3: + container_name: bitcoin-core-3 + networks: + rgb-tests-2: + ipv4_address: 172.30.2.206 + image: bitlightlabs/bitcoind:v27.0 + restart: on-failure + depends_on: + - init-3 + volumes: + - bitcoin-data-3:/data/.bitcoin + entrypoint: /bin/sh + ports: + - "${BITCOIN_RPC_PORT_3:-18445}:18443" + - "28445:18444" + command: + - -c + - | + while [ ! -f /data/.bitcoin/bitcoin.conf ]; do sleep 1; done + bitcoind -regtest -rpcbind=0.0.0.0 -listenonion=0 -discover=0 -dns=0 + + esplora-api-2: + container_name: esplora-api-2 + networks: + - rgb-tests-2 + image: bitlightlabs/esplora-api:latest + volumes: + - bitcoin-data-2:/data/.bitcoin + depends_on: + - bitcoin-core-2 + command: + - -vvvv + - --network + - regtest + - --daemon-dir + - /data/.bitcoin + - --daemon-rpc-addr + - 172.30.2.205:18443 + - --cors + - "*" + - --cookie + - "${RPC_USER:-bitcoin}:${RPC_PASSWORD:-bitcoin}" + - --http-addr + - "0.0.0.0:3000" + - --electrum-rpc-addr + - 0.0.0.0:50001 + ports: + - "${ELECTRUM_PORT_2:-50002}:50001" + - "${API_PORT_2:-3002}:3000" + + esplora-api-3: + container_name: esplora-api-3 + networks: + - rgb-tests-2 + image: bitlightlabs/esplora-api:latest + volumes: + - bitcoin-data-3:/data/.bitcoin + depends_on: + - bitcoin-core-3 + command: + - -vvvv + - --network + - regtest + - --daemon-dir + - /data/.bitcoin + - --daemon-rpc-addr + - 172.30.2.206:18443 + - --cors + - "*" + - --cookie + - "${RPC_USER:-bitcoin}:${RPC_PASSWORD:-bitcoin}" + - --http-addr + - "0.0.0.0:3000" + - --electrum-rpc-addr + - 0.0.0.0:50001 + ports: + - "${ELECTRUM_PORT_3:-50003}:50001" + - "${API_PORT_3:-3003}:3000" + esplora-1: + container_name: esplora-1 + image: bitlightlabs/esplora:latest + environment: + - API_URL=http://127.0.0.1:${API_PORT_1} + ports: + - "${EXPLORE_UI_PORT_1:-5005}:5000" + esplora-2: + container_name: esplora-2 + image: bitlightlabs/esplora:latest + environment: + - API_URL=http://127.0.0.1:${API_PORT_2} + ports: + - "${EXPLORE_UI_PORT_2:-5006}:5000" + esplora-3: + container_name: esplora-3 + image: bitlightlabs/esplora:latest + environment: + - API_URL=http://127.0.0.1:${API_PORT_3} + ports: + - "${EXPLORE_UI_PORT_3:-5007}:5000" diff --git a/tests/docker/start_services.sh b/tests/docker/start_services.sh new file mode 100755 index 0000000..c87152f --- /dev/null +++ b/tests/docker/start_services.sh @@ -0,0 +1,345 @@ +#!/usr/bin/env bash +# +# utility script to run and command regtest services +# + +# Get the directory where the script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$SCRIPT_DIR" + +name="./$(basename "$0")" + +COMPOSE="docker compose -p rgb-tests" +if ! docker compose version >/dev/null; then + echo "could not call docker compose (hint: install docker compose plugin)" + exit 1 +fi + +# Bitcoin CLI commands for each node +BITCOIN_CLI_1="$COMPOSE exec bitcoin-core-1 bitcoin-cli -regtest" +BITCOIN_CLI_2="$COMPOSE exec bitcoin-core-2 bitcoin-cli -regtest" +BITCOIN_CLI_3="$COMPOSE exec bitcoin-core-3 bitcoin-cli -regtest" + +# Node IP addresses +NODE2_IP="172.30.2.205" +NODE3_IP="172.30.2.206" + +INITIAL_BLOCKS=103 +WALLET_NAME="miner" + +# Load environment variables from .env file +if [ -f .env ]; then + export $(grep -v '^#' .env | xargs) +else + echo "ERR: .env file not found" + exit 1 +fi + +_die () { + echo "ERR: $*" + exit 1 +} + +_create_or_load_wallet() { + local cli_cmd=$1 + local node_num=$2 + + echo "Setting up wallet for node $node_num..." + + # Check if wallet is already loaded + if $cli_cmd listwallets 2>/dev/null | grep -q "\"$WALLET_NAME\""; then + echo "Wallet already loaded for node $node_num" + return 0 + fi + + # Check if wallet file exists + if $cli_cmd listwalletdir 2>/dev/null | grep -q "\"$WALLET_NAME\""; then + echo "Loading existing wallet for node $node_num" + if $cli_cmd loadwallet "$WALLET_NAME" 2>/dev/null; then + echo "Successfully loaded wallet for node $node_num" + return 0 + fi + else + echo "Creating new wallet for node $node_num" + if $cli_cmd createwallet "$WALLET_NAME" 2>/dev/null; then + echo "Successfully created wallet for node $node_num" + return 0 + fi + fi + + echo "Failed to create or load wallet for node $node_num" + return 1 +} + +# Function to check if a port is in use +_check_port_in_use() { + local port=$1 + if [[ "$OSTYPE" == "darwin"* ]]; then + # macOS + if [ -n "$(netstat -an | grep LISTEN | grep ".$port")" ]; then + return 0 + else + return 1 + fi + else + # Linux + if [ -n "$(ss -HOlnt "sport = :$port")" ]; then + return 0 + else + return 1 + fi + fi +} + +_connect_nodes() { + # Ensure nodes 2 and 3 are connected to each other + echo "Establishing connection between nodes..." + + # Wait for nodes to be fully started and listening + sleep 5 + + # Clear existing connections + $BITCOIN_CLI_2 clearbanned + $BITCOIN_CLI_3 clearbanned + + # Use 'add' instead of 'onetry' for persistent connections + echo "Adding peer connections..." + $BITCOIN_CLI_2 addnode "$NODE3_IP:18444" "onetry" + $BITCOIN_CLI_3 addnode "$NODE2_IP:18444" "onetry" +} + +_wait_for_sync() { + echo "Waiting for block synchronization..." + local max_attempts=30 + local attempt=1 + + while [ $attempt -le $max_attempts ]; do + local height_2=$($BITCOIN_CLI_2 getblockcount) + local height_3=$($BITCOIN_CLI_3 getblockcount) + + if [ "$height_2" = "$height_3" ]; then + echo "Nodes synchronized at height $height_2" + return 0 + fi + + echo "Attempt $attempt: Node 2 height: $height_2, Node 3 height: $height_3" + sleep 2 + attempt=$((attempt + 1)) + done + + echo "Warning: Synchronization failed after $max_attempts attempts" + return 1 +} + +_check_network_status() { + echo "Checking network status..." + + # Check node 2's network information + echo "Node 2 connections:" + $BITCOIN_CLI_2 getpeerinfo | grep "addr\|subver" + + # Check node 3's network information + echo "Node 3 connections:" + $BITCOIN_CLI_3 getpeerinfo | grep "addr\|subver" +} + +_wait_for_bitcoin_ready() { + local cli_cmd=$1 + local node_num=$2 + local max_attempts=30 + local attempt=1 + + echo "Waiting for node $node_num to be ready..." + while [ $attempt -le $max_attempts ]; do + if $cli_cmd getblockchaininfo >/dev/null 2>&1; then + # Wait a bit more to ensure wallet system is also ready + sleep 2 + echo "Node $node_num is ready" + return 0 + fi + echo "Waiting for node $node_num... (attempt $attempt/$max_attempts)" + sleep 2 + attempt=$((attempt + 1)) + done + + echo "Timeout waiting for node $node_num" + return 1 +} + +_start_services() { + _clean_environment + + # Check exposed ports + EXPOSED_PORTS=( + $BITCOIN_RPC_PORT_1 $ELECTRUM_PORT_1 $API_PORT_1 + $BITCOIN_RPC_PORT_2 $ELECTRUM_PORT_2 $API_PORT_2 + $BITCOIN_RPC_PORT_3 $ELECTRUM_PORT_3 $API_PORT_3 + ) + for port in "${EXPOSED_PORTS[@]}"; do + if _check_port_in_use "$port"; then + _die "port $port is already bound, services can't be started" + fi + done + + echo "Starting services..." + $COMPOSE up -d + + echo "Waiting for services to start..." + sleep 10 + + # Wait for all nodes to be ready + _wait_for_bitcoin_ready "$BITCOIN_CLI_1" "1" || _die "Node 1 failed to start" + _wait_for_bitcoin_ready "$BITCOIN_CLI_2" "2" || _die "Node 2 failed to start" + _wait_for_bitcoin_ready "$BITCOIN_CLI_3" "3" || _die "Node 3 failed to start" + + # Create or load wallets + echo "Setting up wallets..." + _create_or_load_wallet "$BITCOIN_CLI_1" "1" || _die "Failed to setup wallet for node 1" + _create_or_load_wallet "$BITCOIN_CLI_2" "2" || _die "Failed to setup wallet for node 2" + _create_or_load_wallet "$BITCOIN_CLI_3" "3" || _die "Failed to setup wallet for node 3" + + # Node 1 (isolated network) + echo "Generating initial blocks for node 1..." + $BITCOIN_CLI_1 -rpcwallet="$WALLET_NAME" -generate $INITIAL_BLOCKS > /dev/null + + # Node 2 & 3 (shared network) + # Establish and verify node connections + _connect_nodes + + # Generate blocks on node 2 + echo "Generating blocks on node 2..." + $BITCOIN_CLI_2 -rpcwallet="$WALLET_NAME" -generate $INITIAL_BLOCKS > /dev/null + + # Wait for synchronization + _wait_for_sync + + # Verify block heights are the same for nodes 2 and 3 + HEIGHT_2=$($BITCOIN_CLI_2 getblockcount) + HEIGHT_3=$($BITCOIN_CLI_3 getblockcount) + + if [ "$HEIGHT_2" = "$HEIGHT_3" ]; then + echo "Node 2 and Node 3 are synchronized at height $HEIGHT_2" + else + echo "Warning: Node 2 ($HEIGHT_2) and Node 3 ($HEIGHT_3) heights differ" + fi + + # Wait for Esplora services to start + echo "Waiting for Esplora services to start..." + sleep 10 + + echo "Setup completed successfully" +} + +_stop_services() { + echo "Stopping services..." + $COMPOSE down +} + +_clean_environment() { + echo "Cleaning up environment..." + # Stop all services + $COMPOSE down --remove-orphans + + # Remove all related docker volumes + echo "Removing volumes..." + docker volume ls -q | grep "rgb-tests" | xargs -r docker volume rm + + # Remove related docker networks + echo "Removing networks..." + docker network ls --filter name=rgb-tests -q | xargs -r docker network rm + + # Remove wallet data directory + echo "Removing wallet data..." + rm -rf data{core,index,ldk0,ldk1,ldk2} + + echo "Environment cleaned successfully" +} + +_mine() { + local node=$1 + local blocks=$2 + case $node in + 1) + $BITCOIN_CLI_1 -rpcwallet="$WALLET_NAME" -generate $blocks > /dev/null + ;; + 2) + $BITCOIN_CLI_2 -rpcwallet="$WALLET_NAME" -generate $blocks > /dev/null + ;; + 3) + $BITCOIN_CLI_3 -rpcwallet="$WALLET_NAME" -generate $blocks > /dev/null + ;; + *) + _die "Invalid node number: $node" + ;; + esac +} + +_help() { + echo "$name [-h|--help]" + echo " show this help message" + echo + echo "$name start" + echo " stop services, clean up, start services," + echo " create bitcoind wallets and generate initial blocks" + echo + echo "$name stop" + echo " stop services (preserving data)" + echo + echo "$name clean" + echo " clean up environment (remove volumes, networks)" + echo + echo "$name status" + echo " check network connection status" + echo + echo "$name mine " + echo " mine the requested number of blocks on specified node (1, 2, or 3)" +} + +# cmdline arguments +[ -z "$1" ] && _help +while [ -n "$1" ]; do + case $1 in + -h|--help) + _help + exit 0 + ;; + start) + start=1 + ;; + stop) + stop=1 + ;; + clean) + clean=1 + ;; + status) + _check_network_status + ;; + mine) + [ -n "$2" ] || _die "node number is required" + [ -n "$3" ] || _die "num blocks is required" + NODE_NUM="$2" + NUM_BLOCKS="$3" + mine=1 + shift 2 + ;; + *) + _die "unsupported argument \"$1\"" + ;; + esac + shift +done + +# start services if requested +[ "$start" = "1" ] && _start_services + +# stop services if requested +[ "$stop" = "1" ] && _stop_services + +# clean environment if requested +[ "$clean" = "1" ] && _clean_environment + +# mine blocks if requested +[ "$mine" = "1" ] && _mine $NODE_NUM $NUM_BLOCKS + +exit 0 diff --git a/tests/fixtures/attack_bundles_pubWitness_data_input_sequence.yaml b/tests/fixtures/attack_bundles_pubWitness_data_input_sequence.yaml deleted file mode 100644 index e47d027..0000000 --- a/tests/fixtures/attack_bundles_pubWitness_data_input_sequence.yaml +++ /dev/null @@ -1,1138 +0,0 @@ -version: v2 -transfer: true -terminals: - 3bb2645029b3de98be6c3ed5ce3332b8591f59c693146a007b75db5cfdb7c7b8: - chain: bitcoin - data: e1c963ea4a2d4e21f870c713a76d0397a0cc197aece1f53a66ae9febf122bb50 -genesis: - ffv: 0 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - flags: null - timestamp: 1728925859 - issuer: ssi:anonymous - testnet: true - altLayers1: [] - assetTags: - 4000: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - metadata: {} - globals: - 2000: - - 074e494154434b520e4e4941206173736574206e616d650002 - 2001: - - 09004e4941207465726d7300 - 2010: - - 9a02000000000000 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: 22f0538e189f32922e55daf6fa0b7120bc01de8520a9a4c80655fdaf70272ac0 - vout: 1 - blinding: 7704601239148887312 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null -extensions: [] -bundles: -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: a5c3085efe8dfdba0fa0e11d81bf90cdcac27c0af496c4de1a2fd9659948ffce:0 - sigScript: '' - sequence: 1 - witness: [] - outputs: - - value: 99999200 - scriptPubkey: 001430d944c2d49db5c315c49e13aab8cad8b9415cac - - value: 0 - scriptPubkey: 6a20669e87f4fe2acf39e58ef94c4a2f81791b7848acac344cd8a2e562f4777acc7f - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 0d4042fb3c309aa40bff3159cee3a0ca87c4efc804a5347aa1a363d7244a88f7 - - e56d0e3dbadefb489899917dbc2e1dbf0c49c3ff155e178ef52feab2f351fc7c - - 4edc7f8808488b46c10bedf910818a9afbe2512c1f08a436a7b3db244f22ac85 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3 - knownTransitions: - 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 10251942175724995735 - state: - value: 616 - blinding: 361c123b494b218e332794a2390dc6d5cc7c332f64cf8764b6dfb3e04e56c9fc - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - - seal: - chain: bitcoin - data: 108b3912eb0b836427f235bafe449f3153c2aae08887b948a3d8529f17b19b95 - state: - value: 50 - blinding: 48626c4335335cf04b56e9dc4570b7a8b2024b4f19aef719c79eca9e3027b482 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: 22f0538e189f32922e55daf6fa0b7120bc01de8520a9a4c80655fdaf70272ac0:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 99999600 - scriptPubkey: 00141d66111f9daca8769c3ab2b0fe14354b6198b29c - - value: 0 - scriptPubkey: 6a20a02ab7dd75b9911b540419440ebe8f5be0742f76fd9fdaf5e69ebb30f38d3f11 - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 0ae6caac7df078206a7af28b0a885098f743d49b92cdb3485558b804492a5be5 - - 843d661f6822486889697a7446a6a9bd1e123921c6dafdde687140cf863a9403 - - 040c8d2b550cc8f3bd210535dbf482f91e7fe62989168c1ed87eebf2b4f35be3 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e - knownTransitions: - fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 65535 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 260ba748cbd95421f871fcea5b5a8dca954ed9af5fed4613def3759a33bf11b8 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 7687739675014878388 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: d077ea7e3a55a215893a18e82cb03fda0f50619893e4aee0ba70b014e6d63248:0 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 99998800 - scriptPubkey: 00146ab6fe162c087a01a717d2b6d4bbef87829cec24 - - value: 0 - scriptPubkey: 6a2088b706bf16e225b5d438f48c8c1abc544e807bb7fb99e6fc8ca460d4de62d1b0 - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 91246094600e4cae70d42147330754f25ef710118c7bc3aa963b1a8900125b83 - - 58bb69c807310413032dd30a245738b48f1a5cb8645f55b8f089489ae16b0533 - - 500d82630b8bb4a1bcb8973500acae7114dc0d5ef77b748a60b4d93aa9375ca1 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: c04da8609a2a8ddf7e0e9847f4ebd6758b1091bceeda10094b24352c97840ea2 - knownTransitions: - c04da8609a2a8ddf7e0e9847f4ebd6758b1091bceeda10094b24352c97840ea2: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 9888072140771099372 - state: - value: 539 - blinding: ae89403cecbdb782ddba50b592d9590bb664bb3d4dc9f7772f7c6611f4755345 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - - seal: - chain: bitcoin - data: e1c963ea4a2d4e21f870c713a76d0397a0cc197aece1f53a66ae9febf122bb50 - state: - value: 77 - blinding: 8792d1fe5c8d6a0b556d43eca6346dc8d0c654d8c64e30294735ac5b2a17b7f8 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -schema: - ffv: 0 - flags: null - name: NonInflatableAsset - timestamp: 1713343888 - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - metaTypes: {} - globalTypes: - 2000: - reserved: null - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - maxItems: 1 - 2001: - reserved: null - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - maxItems: 1 - 2010: - reserved: null - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - maxItems: 1 - ownedTypes: - 4000: !fungible unsigned64Bit - valencyTypes: [] - genesis: - metadata: [] - globals: - 2000: once - 2001: once - 2010: once - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 9 - extensions: {} - transitions: - 10000: - metadata: [] - globals: {} - inputs: - 4000: onceOrMore - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 0 - reserved: null -ifaces: - ? version: v1 - name: RGB20Fixed - inherits: - - rgb:ifc:Vk9c4$Ny-Fv0J6tg-pDF05CE-312oCWh-fENNuia-GYbEu18#adios-alert-never - - rgb:ifc:13N6PRwT-T68!FGY-lBwX2cm-qesgJ11-j0nQkM1-WSCJFj4#ariel-gizmo-evita - - rgb:ifc:naFrAfgG-Kfu$A!c-3L!bC$4-s1LWJQV-4Iv!62u-4B3ab8Y#mailbox-dialog-iron - - rgb:ifc:w3Lk9Mt3-gKt$n5y-TYpVGg0-IDpK0p9-sHQ!hb6-m2Qr3a0#unicorn-reward-ladder - timestamp: 1711405444 - metadata: {} - globalState: - issuedSupply: - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - required: true - multiple: false - spec: - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - required: true - multiple: false - terms: - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - required: true - multiple: false - assignments: - assetOwner: - ownedState: amount - public: false - required: true - multiple: true - valencies: {} - genesis: - modifier: abstract - metadata: [] - globals: - issuedSupply: once - spec: once - terms: once - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - issuedMismatch - transitions: - transfer: - modifier: abstract - optional: false - metadata: [] - globals: {} - inputs: - assetOwner: onceOrMore - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - nonEqualAmounts - defaultAssignment: assetOwner - extensions: {} - defaultOperation: transfer - errors: - issuedMismatch: supply specified as a global parameter doesn't match the issued supply allocated to the asset owners - nonEqualAmounts: the sum of spent assets doesn't equal to the sum of assets in outputs - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - : version: v1 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - ifaceId: rgb:ifc:$iUnO9aO-1xhqUd6-1Jm5S5!-wM3ngby-5GVEylQ-ZTAMYDk#tornado-pioneer-bucket - timestamp: 1713343888 - metadata: [] - globalState: - - id: 2000 - name: spec - reserved: null - - id: 2001 - name: terms - reserved: null - - id: 2010 - name: issuedSupply - reserved: null - assignments: - - id: 4000 - name: assetOwner - reserved: null - valencies: [] - transitions: - - id: 10000 - name: transfer - reserved: null - extensions: [] - errors: - - id: 0 - name: nonEqualAmounts - reserved: null - - id: 1 - name: issuedMismatch - reserved: null - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w -supplements: [] -types: - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751: !List - - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355 - - min: 0 - max: 7 - 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01: !Tuple - - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154 - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042: !Primitive 64 - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb: !Tuple - - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90 - 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd: !Array - - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042 - - 32 - 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997 - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73: !Enum - - name: excl - tag: 33 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: amp - tag: 38 - - name: plus - tag: 43 - - name: dash - tag: 45 - - name: dot - tag: 46 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4: !Tuple - - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a: !Struct - - name: type - ty: b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660 - - name: digest - ty: 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd - 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7 - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8: !Enum - - name: space - tag: 32 - - name: excl - tag: 33 - - name: quotes - tag: 34 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: percent - tag: 37 - - name: ampersand - tag: 38 - - name: apostrophe - tag: 39 - - name: bracketL - tag: 40 - - name: bracketR - tag: 41 - - name: asterisk - tag: 42 - - name: plus - tag: 43 - - name: comma - tag: 44 - - name: minus - tag: 45 - - name: dot - tag: 46 - - name: slash - tag: 47 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: colon - tag: 58 - - name: semiColon - tag: 59 - - name: less - tag: 60 - - name: equal - tag: 61 - - name: greater - tag: 62 - - name: question - tag: 63 - - name: at - tag: 64 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: sqBracketL - tag: 91 - - name: backSlash - tag: 92 - - name: sqBracketR - tag: 93 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: backtick - tag: 96 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - - name: cBracketL - tag: 123 - - name: pipe - tag: 124 - - name: cBracketR - tag: 125 - - name: tilde - tag: 126 - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 0 - max: 65535 - 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa: !Tuple - - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f - 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7: !Struct - - name: text - ty: 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01 - - name: media - ty: e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81 - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f: !Primitive 8 - 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22: !Enum - - name: indivisible - tag: 0 - - name: deci - tag: 1 - - name: centi - tag: 2 - - name: milli - tag: 3 - - name: deciMilli - tag: 4 - - name: centiMilli - tag: 5 - - name: micro - tag: 6 - - name: deciMicro - tag: 7 - - name: centiMicro - tag: 8 - - name: nano - tag: 9 - - name: deciNano - tag: 10 - - name: centiNano - tag: 11 - - name: pico - tag: 12 - - name: deciPico - tag: 13 - - name: centiPico - tag: 14 - - name: femto - tag: 15 - - name: deciFemto - tag: 16 - - name: centiFemto - tag: 17 - - name: atto - tag: 18 - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f: !Tuple - - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2 - - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751 - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355: !Enum - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 1 - max: 255 - 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d: !Tuple - - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4 - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2: !Enum - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84: !Tuple - - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f - b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997: !Tuple - - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660: !Struct - - name: type - ty: 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - - name: subtype - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - - name: charset - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46: !List - - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73 - - min: 0 - max: 63 - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4: !Tuple - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc - caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7: !Tuple - - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4 - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90: !Tuple - - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1 - - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46 - d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01: !Struct - - name: ticker - ty: 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa - - name: name - ty: 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d - - name: details - ty: 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888 - - name: precision - ty: 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22 - d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c: !Primitive 0 - dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548: !Tuple - - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a - e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548 - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc: !List - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - min: 0 - max: 39 - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1: !Enum - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78: UnicodeChar -scripts: -- isae: - - ALU - - BPDIGEST - - RGB - code: - - 11 - - 0 - - 0 - - 0 - - 208 - - 160 - - 15 - - 1 - - 7 - - 11 - - 0 - - 1 - - 0 - - 11 - - 8 - - 0 - - 0 - - 11 - - 1 - - 2 - - 0 - - 200 - - 218 - - 7 - - 1 - - 57 - - 48 - - 0 - - 209 - - 160 - - 15 - - 1 - - 7 - data: - - 0 - - 1 - - 0 - - 0 - libs: [] -attachments: {} -signatures: {} diff --git a/tests/fixtures/attack_chain.yaml b/tests/fixtures/attack_chain.yaml deleted file mode 100644 index 21e9889..0000000 --- a/tests/fixtures/attack_chain.yaml +++ /dev/null @@ -1,1138 +0,0 @@ -version: v2 -transfer: true -terminals: - 3bb2645029b3de98be6c3ed5ce3332b8591f59c693146a007b75db5cfdb7c7b8: - chain: liquid - data: e1c963ea4a2d4e21f870c713a76d0397a0cc197aece1f53a66ae9febf122bb50 -genesis: - ffv: 0 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - flags: null - timestamp: 1728925859 - issuer: ssi:anonymous - testnet: true - altLayers1: [] - assetTags: - 4000: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - metadata: {} - globals: - 2000: - - 074e494154434b520e4e4941206173736574206e616d650002 - 2001: - - 09004e4941207465726d7300 - 2010: - - 9a02000000000000 - assignments: - 4000: - type: fungible - items: - - seal: - chain: liquid - data: - method: opretFirst - txid: 22f0538e189f32922e55daf6fa0b7120bc01de8520a9a4c80655fdaf70272ac0 - vout: 1 - blinding: 7704601239148887312 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null -extensions: [] -bundles: -- pubWitness: - chain: liquid - data: !tx - version: 2 - inputs: - - prevOutput: a5c3085efe8dfdba0fa0e11d81bf90cdcac27c0af496c4de1a2fd9659948ffce:0 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 99999200 - scriptPubkey: 001430d944c2d49db5c315c49e13aab8cad8b9415cac - - value: 0 - scriptPubkey: 6a20669e87f4fe2acf39e58ef94c4a2f81791b7848acac344cd8a2e562f4777acc7f - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 0d4042fb3c309aa40bff3159cee3a0ca87c4efc804a5347aa1a363d7244a88f7 - - e56d0e3dbadefb489899917dbc2e1dbf0c49c3ff155e178ef52feab2f351fc7c - - 4edc7f8808488b46c10bedf910818a9afbe2512c1f08a436a7b3db244f22ac85 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3 - knownTransitions: - 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: liquid - data: - method: opretFirst - txid: null - vout: 0 - blinding: 10251942175724995735 - state: - value: 616 - blinding: 361c123b494b218e332794a2390dc6d5cc7c332f64cf8764b6dfb3e04e56c9fc - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - - seal: - chain: liquid - data: 108b3912eb0b836427f235bafe449f3153c2aae08887b948a3d8529f17b19b95 - state: - value: 50 - blinding: 48626c4335335cf04b56e9dc4570b7a8b2024b4f19aef719c79eca9e3027b482 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: liquid - data: !tx - version: 2 - inputs: - - prevOutput: 22f0538e189f32922e55daf6fa0b7120bc01de8520a9a4c80655fdaf70272ac0:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 99999600 - scriptPubkey: 00141d66111f9daca8769c3ab2b0fe14354b6198b29c - - value: 0 - scriptPubkey: 6a20a02ab7dd75b9911b540419440ebe8f5be0742f76fd9fdaf5e69ebb30f38d3f11 - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 0ae6caac7df078206a7af28b0a885098f743d49b92cdb3485558b804492a5be5 - - 843d661f6822486889697a7446a6a9bd1e123921c6dafdde687140cf863a9403 - - 040c8d2b550cc8f3bd210535dbf482f91e7fe62989168c1ed87eebf2b4f35be3 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e - knownTransitions: - fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 65535 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 260ba748cbd95421f871fcea5b5a8dca954ed9af5fed4613def3759a33bf11b8 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: liquid - data: - method: opretFirst - txid: null - vout: 0 - blinding: 7687739675014878388 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: liquid - data: !tx - version: 2 - inputs: - - prevOutput: d077ea7e3a55a215893a18e82cb03fda0f50619893e4aee0ba70b014e6d63248:0 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 99998800 - scriptPubkey: 00146ab6fe162c087a01a717d2b6d4bbef87829cec24 - - value: 0 - scriptPubkey: 6a2088b706bf16e225b5d438f48c8c1abc544e807bb7fb99e6fc8ca460d4de62d1b0 - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 91246094600e4cae70d42147330754f25ef710118c7bc3aa963b1a8900125b83 - - 58bb69c807310413032dd30a245738b48f1a5cb8645f55b8f089489ae16b0533 - - 500d82630b8bb4a1bcb8973500acae7114dc0d5ef77b748a60b4d93aa9375ca1 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: c04da8609a2a8ddf7e0e9847f4ebd6758b1091bceeda10094b24352c97840ea2 - knownTransitions: - c04da8609a2a8ddf7e0e9847f4ebd6758b1091bceeda10094b24352c97840ea2: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: liquid - data: - method: opretFirst - txid: null - vout: 0 - blinding: 9888072140771099372 - state: - value: 539 - blinding: ae89403cecbdb782ddba50b592d9590bb664bb3d4dc9f7772f7c6611f4755345 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - - seal: - chain: liquid - data: e1c963ea4a2d4e21f870c713a76d0397a0cc197aece1f53a66ae9febf122bb50 - state: - value: 77 - blinding: 8792d1fe5c8d6a0b556d43eca6346dc8d0c654d8c64e30294735ac5b2a17b7f8 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -schema: - ffv: 0 - flags: null - name: NonInflatableAsset - timestamp: 1713343888 - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - metaTypes: {} - globalTypes: - 2000: - reserved: null - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - maxItems: 1 - 2001: - reserved: null - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - maxItems: 1 - 2010: - reserved: null - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - maxItems: 1 - ownedTypes: - 4000: !fungible unsigned64Bit - valencyTypes: [] - genesis: - metadata: [] - globals: - 2000: once - 2001: once - 2010: once - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 9 - extensions: {} - transitions: - 10000: - metadata: [] - globals: {} - inputs: - 4000: onceOrMore - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 0 - reserved: null -ifaces: - ? version: v1 - name: RGB20Fixed - inherits: - - rgb:ifc:Vk9c4$Ny-Fv0J6tg-pDF05CE-312oCWh-fENNuia-GYbEu18#adios-alert-never - - rgb:ifc:13N6PRwT-T68!FGY-lBwX2cm-qesgJ11-j0nQkM1-WSCJFj4#ariel-gizmo-evita - - rgb:ifc:naFrAfgG-Kfu$A!c-3L!bC$4-s1LWJQV-4Iv!62u-4B3ab8Y#mailbox-dialog-iron - - rgb:ifc:w3Lk9Mt3-gKt$n5y-TYpVGg0-IDpK0p9-sHQ!hb6-m2Qr3a0#unicorn-reward-ladder - timestamp: 1711405444 - metadata: {} - globalState: - issuedSupply: - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - required: true - multiple: false - spec: - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - required: true - multiple: false - terms: - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - required: true - multiple: false - assignments: - assetOwner: - ownedState: amount - public: false - required: true - multiple: true - valencies: {} - genesis: - modifier: abstract - metadata: [] - globals: - issuedSupply: once - spec: once - terms: once - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - issuedMismatch - transitions: - transfer: - modifier: abstract - optional: false - metadata: [] - globals: {} - inputs: - assetOwner: onceOrMore - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - nonEqualAmounts - defaultAssignment: assetOwner - extensions: {} - defaultOperation: transfer - errors: - issuedMismatch: supply specified as a global parameter doesn't match the issued supply allocated to the asset owners - nonEqualAmounts: the sum of spent assets doesn't equal to the sum of assets in outputs - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - : version: v1 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - ifaceId: rgb:ifc:$iUnO9aO-1xhqUd6-1Jm5S5!-wM3ngby-5GVEylQ-ZTAMYDk#tornado-pioneer-bucket - timestamp: 1713343888 - metadata: [] - globalState: - - id: 2000 - name: spec - reserved: null - - id: 2001 - name: terms - reserved: null - - id: 2010 - name: issuedSupply - reserved: null - assignments: - - id: 4000 - name: assetOwner - reserved: null - valencies: [] - transitions: - - id: 10000 - name: transfer - reserved: null - extensions: [] - errors: - - id: 0 - name: nonEqualAmounts - reserved: null - - id: 1 - name: issuedMismatch - reserved: null - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w -supplements: [] -types: - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751: !List - - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355 - - min: 0 - max: 7 - 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01: !Tuple - - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154 - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042: !Primitive 64 - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb: !Tuple - - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90 - 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd: !Array - - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042 - - 32 - 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997 - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73: !Enum - - name: excl - tag: 33 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: amp - tag: 38 - - name: plus - tag: 43 - - name: dash - tag: 45 - - name: dot - tag: 46 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4: !Tuple - - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a: !Struct - - name: type - ty: b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660 - - name: digest - ty: 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd - 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7 - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8: !Enum - - name: space - tag: 32 - - name: excl - tag: 33 - - name: quotes - tag: 34 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: percent - tag: 37 - - name: ampersand - tag: 38 - - name: apostrophe - tag: 39 - - name: bracketL - tag: 40 - - name: bracketR - tag: 41 - - name: asterisk - tag: 42 - - name: plus - tag: 43 - - name: comma - tag: 44 - - name: minus - tag: 45 - - name: dot - tag: 46 - - name: slash - tag: 47 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: colon - tag: 58 - - name: semiColon - tag: 59 - - name: less - tag: 60 - - name: equal - tag: 61 - - name: greater - tag: 62 - - name: question - tag: 63 - - name: at - tag: 64 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: sqBracketL - tag: 91 - - name: backSlash - tag: 92 - - name: sqBracketR - tag: 93 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: backtick - tag: 96 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - - name: cBracketL - tag: 123 - - name: pipe - tag: 124 - - name: cBracketR - tag: 125 - - name: tilde - tag: 126 - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 0 - max: 65535 - 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa: !Tuple - - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f - 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7: !Struct - - name: text - ty: 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01 - - name: media - ty: e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81 - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f: !Primitive 8 - 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22: !Enum - - name: indivisible - tag: 0 - - name: deci - tag: 1 - - name: centi - tag: 2 - - name: milli - tag: 3 - - name: deciMilli - tag: 4 - - name: centiMilli - tag: 5 - - name: micro - tag: 6 - - name: deciMicro - tag: 7 - - name: centiMicro - tag: 8 - - name: nano - tag: 9 - - name: deciNano - tag: 10 - - name: centiNano - tag: 11 - - name: pico - tag: 12 - - name: deciPico - tag: 13 - - name: centiPico - tag: 14 - - name: femto - tag: 15 - - name: deciFemto - tag: 16 - - name: centiFemto - tag: 17 - - name: atto - tag: 18 - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f: !Tuple - - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2 - - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751 - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355: !Enum - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 1 - max: 255 - 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d: !Tuple - - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4 - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2: !Enum - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84: !Tuple - - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f - b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997: !Tuple - - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660: !Struct - - name: type - ty: 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - - name: subtype - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - - name: charset - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46: !List - - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73 - - min: 0 - max: 63 - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4: !Tuple - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc - caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7: !Tuple - - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4 - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90: !Tuple - - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1 - - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46 - d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01: !Struct - - name: ticker - ty: 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa - - name: name - ty: 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d - - name: details - ty: 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888 - - name: precision - ty: 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22 - d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c: !Primitive 0 - dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548: !Tuple - - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a - e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548 - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc: !List - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - min: 0 - max: 39 - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1: !Enum - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78: UnicodeChar -scripts: -- isae: - - ALU - - BPDIGEST - - RGB - code: - - 11 - - 0 - - 0 - - 0 - - 208 - - 160 - - 15 - - 1 - - 7 - - 11 - - 0 - - 1 - - 0 - - 11 - - 8 - - 0 - - 0 - - 11 - - 1 - - 2 - - 0 - - 200 - - 218 - - 7 - - 1 - - 57 - - 48 - - 0 - - 209 - - 160 - - 15 - - 1 - - 7 - data: - - 0 - - 1 - - 0 - - 0 - libs: [] -attachments: {} -signatures: {} diff --git a/tests/fixtures/attack_genesis_schema_id.yaml b/tests/fixtures/attack_genesis_schema_id.yaml deleted file mode 100644 index 94cc24c..0000000 --- a/tests/fixtures/attack_genesis_schema_id.yaml +++ /dev/null @@ -1,1149 +0,0 @@ -version: v2 -transfer: true -terminals: {} -genesis: - ffv: 0 - schemaId: rgb:sch:cJjPZfUpkOqIWhpCTqYJtFYzLfz$AB3JNxIEOJZYn28#circus-version-silence - flags: null - timestamp: 1728926035 - issuer: ssi:anonymous - testnet: true - altLayers1: [] - assetTags: - 4000: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - metadata: {} - globals: - 2000: - - 074e494154434b520e4e4941206173736574206e616d650002 - 2001: - - 09004e4941207465726d7300 - 2010: - - 9a02000000000000 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: 39f4d1888d1d994a2649397d34bfcaf8a9f7de2d6369dd1d42e0c61a26b4384b - vout: 1 - blinding: 7943510731595037200 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null -extensions: [] -bundles: -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: c269055b7750a234087c11acd7a408172cb84d8fc6af0ded42d8a8cbea6712e9:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 - - value: 99981200 - scriptPubkey: 0014ceb732c6400f984d3258c202811ef439234ff028 - - value: 0 - scriptPubkey: 6a20efce72c00a4dafa508d223854191b9bc534505d7b40841136ea57454bcd8f62e - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 4 - cofactor: 1 - path: - - 59fb64885c9d21d566c630261ebaf61e6fdfb90fd755734580e2853606e04468 - - 972bd31741970dcfdcb1fd6e1e0cb86b43a95cdf9be16e26b20f7efb55b8815a - - 59c4bea42d613b9b4d9190c70713db38fcb1213e1384390305c9f41b105e7ad7 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 93ff8f77c5f41ebdfb417b9f30a603e2b48a0db75d5a0e520495954e564f62f6 - knownTransitions: - 93ff8f77c5f41ebdfb417b9f30a603e2b48a0db75d5a0e520495954e564f62f6: - ffv: 0 - contractId: rgb:P9y8fj2n-Hjyhxbb-FSv9Jb6-xVz3qn$-laXX8N6-hzNhlHQ - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 76fc3455d84d793361211daa2a85be764b9bebc559dd2958833bf6ab153fa9a3 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 10355153668244730300 - state: - value: 50 - blinding: 6ba480e64c69b4e53fe7c76e5c79bb79e8d1a442ba405e9b568612b0014dc452 - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 1 - blinding: 4411272172758969930 - state: - value: 616 - blinding: 12d9fd983214c9993e96b7102204c30495acda3bc43e1fe327f86bce7d30ba2c - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: d84c37b6c6616184c454c815d970505bed9b3a3723a4445dd1289dc708bc80b3:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 - - value: 99971800 - scriptPubkey: 0014b63cbe65e66aaec213d9e25a2ff8cd4e4f3c47d0 - - value: 0 - scriptPubkey: 6a2036831c40589897909e67d439cba95004d53280635e2ca66b6e53da52551f957c - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 4 - cofactor: 1 - path: - - ade25d6370736e013b7148b4e223030112c4dff704d992e0a8d92073df669c2f - - f478b2c344da010822be93fb7405c56c0b95867ce56582a6c4f647b678fba56e - - 9461109d34187938798bf29433c2b3f11f08ed7f7c8831fcceeab43874f11689 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 295cbd02dbfeddee5c9691cfcc2b5c59b284c8130ad1c9e2cfb867b45dc24dec - knownTransitions: - 295cbd02dbfeddee5c9691cfcc2b5c59b284c8130ad1c9e2cfb867b45dc24dec: - ffv: 0 - contractId: rgb:P9y8fj2n-Hjyhxbb-FSv9Jb6-xVz3qn$-laXX8N6-hzNhlHQ - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 93ff8f77c5f41ebdfb417b9f30a603e2b48a0db75d5a0e520495954e564f62f6 - ty: 4000 - no: 1 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 5517491780835545414 - state: - value: 77 - blinding: ab9ad5d441db401474f2f15c2d7940cec37d8b1c962dc20752256f95fdfd1634 - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 1 - blinding: 17151752316201612509 - state: - value: 539 - blinding: 673f27c3f0398984c9a3c5b3f48b82348cde2c05dd58fe1795a55ac54f69e539 - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: 39f4d1888d1d994a2649397d34bfcaf8a9f7de2d6369dd1d42e0c61a26b4384b:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 - - value: 99990600 - scriptPubkey: 00147c22e5543af0a3dca1c89ae5ffbf6cadd03a1bb3 - - value: 0 - scriptPubkey: 6a209f6aed701fb9da0762a238d96e0b203220a609a9afaba47ea71ba96e08065458 - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 4 - cofactor: 1 - path: - - 09a4be7f9ba65f3e4588a93061fe429c8e257de6cb5194a82c1e4dc5d6ff48fd - - cdc9e7844302abff47462927f67cfc6b350a5023dcceb1798eeea250dcce7052 - - 6ef2b8c22960c49c7be94ea27b5909ac60dbbd69fe057d5475795a35802bf24a - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 76fc3455d84d793361211daa2a85be764b9bebc559dd2958833bf6ab153fa9a3 - knownTransitions: - 76fc3455d84d793361211daa2a85be764b9bebc559dd2958833bf6ab153fa9a3: - ffv: 0 - contractId: rgb:P9y8fj2n-Hjyhxbb-FSv9Jb6-xVz3qn$-laXX8N6-hzNhlHQ - nonce: 18446744073709551615 - transitionType: 65535 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 3fdcbc7e3da71e3ca1c5b6c54aff496fac55cf7aa7fe56975fc37a8733619474 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 1 - blinding: 16141698382146724670 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null - witness: null -schema: - ffv: 0 - flags: null - name: NonInflatableAsset - timestamp: 1713343888 - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - metaTypes: {} - globalTypes: - 2000: - reserved: null - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - maxItems: 1 - 2001: - reserved: null - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - maxItems: 1 - 2010: - reserved: null - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - maxItems: 1 - ownedTypes: - 4000: !fungible unsigned64Bit - valencyTypes: [] - genesis: - metadata: [] - globals: - 2000: once - 2001: once - 2010: once - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 9 - extensions: {} - transitions: - 10000: - metadata: [] - globals: {} - inputs: - 4000: onceOrMore - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 0 - reserved: null -ifaces: - ? version: v1 - name: RGB20Fixed - inherits: - - rgb:ifc:Vk9c4$Ny-Fv0J6tg-pDF05CE-312oCWh-fENNuia-GYbEu18#adios-alert-never - - rgb:ifc:13N6PRwT-T68!FGY-lBwX2cm-qesgJ11-j0nQkM1-WSCJFj4#ariel-gizmo-evita - - rgb:ifc:naFrAfgG-Kfu$A!c-3L!bC$4-s1LWJQV-4Iv!62u-4B3ab8Y#mailbox-dialog-iron - - rgb:ifc:w3Lk9Mt3-gKt$n5y-TYpVGg0-IDpK0p9-sHQ!hb6-m2Qr3a0#unicorn-reward-ladder - timestamp: 1711405444 - metadata: {} - globalState: - issuedSupply: - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - required: true - multiple: false - spec: - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - required: true - multiple: false - terms: - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - required: true - multiple: false - assignments: - assetOwner: - ownedState: amount - public: false - required: true - multiple: true - valencies: {} - genesis: - modifier: abstract - metadata: [] - globals: - issuedSupply: once - spec: once - terms: once - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - issuedMismatch - transitions: - transfer: - modifier: abstract - optional: false - metadata: [] - globals: {} - inputs: - assetOwner: onceOrMore - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - nonEqualAmounts - defaultAssignment: assetOwner - extensions: {} - defaultOperation: transfer - errors: - issuedMismatch: supply specified as a global parameter doesn't match the issued supply allocated to the asset owners - nonEqualAmounts: the sum of spent assets doesn't equal to the sum of assets in outputs - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - : version: v1 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - ifaceId: rgb:ifc:$iUnO9aO-1xhqUd6-1Jm5S5!-wM3ngby-5GVEylQ-ZTAMYDk#tornado-pioneer-bucket - timestamp: 1713343888 - metadata: [] - globalState: - - id: 2000 - name: spec - reserved: null - - id: 2001 - name: terms - reserved: null - - id: 2010 - name: issuedSupply - reserved: null - assignments: - - id: 4000 - name: assetOwner - reserved: null - valencies: [] - transitions: - - id: 10000 - name: transfer - reserved: null - extensions: [] - errors: - - id: 0 - name: nonEqualAmounts - reserved: null - - id: 1 - name: issuedMismatch - reserved: null - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w -supplements: [] -types: - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751: !List - - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355 - - min: 0 - max: 7 - 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01: !Tuple - - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154 - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042: !Primitive 64 - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb: !Tuple - - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90 - 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd: !Array - - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042 - - 32 - 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997 - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73: !Enum - - name: excl - tag: 33 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: amp - tag: 38 - - name: plus - tag: 43 - - name: dash - tag: 45 - - name: dot - tag: 46 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4: !Tuple - - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a: !Struct - - name: type - ty: b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660 - - name: digest - ty: 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd - 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7 - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8: !Enum - - name: space - tag: 32 - - name: excl - tag: 33 - - name: quotes - tag: 34 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: percent - tag: 37 - - name: ampersand - tag: 38 - - name: apostrophe - tag: 39 - - name: bracketL - tag: 40 - - name: bracketR - tag: 41 - - name: asterisk - tag: 42 - - name: plus - tag: 43 - - name: comma - tag: 44 - - name: minus - tag: 45 - - name: dot - tag: 46 - - name: slash - tag: 47 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: colon - tag: 58 - - name: semiColon - tag: 59 - - name: less - tag: 60 - - name: equal - tag: 61 - - name: greater - tag: 62 - - name: question - tag: 63 - - name: at - tag: 64 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: sqBracketL - tag: 91 - - name: backSlash - tag: 92 - - name: sqBracketR - tag: 93 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: backtick - tag: 96 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - - name: cBracketL - tag: 123 - - name: pipe - tag: 124 - - name: cBracketR - tag: 125 - - name: tilde - tag: 126 - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 0 - max: 65535 - 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa: !Tuple - - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f - 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7: !Struct - - name: text - ty: 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01 - - name: media - ty: e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81 - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f: !Primitive 8 - 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22: !Enum - - name: indivisible - tag: 0 - - name: deci - tag: 1 - - name: centi - tag: 2 - - name: milli - tag: 3 - - name: deciMilli - tag: 4 - - name: centiMilli - tag: 5 - - name: micro - tag: 6 - - name: deciMicro - tag: 7 - - name: centiMicro - tag: 8 - - name: nano - tag: 9 - - name: deciNano - tag: 10 - - name: centiNano - tag: 11 - - name: pico - tag: 12 - - name: deciPico - tag: 13 - - name: centiPico - tag: 14 - - name: femto - tag: 15 - - name: deciFemto - tag: 16 - - name: centiFemto - tag: 17 - - name: atto - tag: 18 - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f: !Tuple - - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2 - - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751 - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355: !Enum - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 1 - max: 255 - 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d: !Tuple - - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4 - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2: !Enum - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84: !Tuple - - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f - b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997: !Tuple - - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660: !Struct - - name: type - ty: 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - - name: subtype - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - - name: charset - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46: !List - - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73 - - min: 0 - max: 63 - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4: !Tuple - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc - caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7: !Tuple - - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4 - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90: !Tuple - - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1 - - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46 - d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01: !Struct - - name: ticker - ty: 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa - - name: name - ty: 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d - - name: details - ty: 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888 - - name: precision - ty: 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22 - d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c: !Primitive 0 - dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548: !Tuple - - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a - e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548 - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc: !List - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - min: 0 - max: 39 - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1: !Enum - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78: UnicodeChar -scripts: -- isae: - - ALU - - BPDIGEST - - RGB - code: - - 11 - - 0 - - 0 - - 0 - - 208 - - 160 - - 15 - - 1 - - 7 - - 11 - - 0 - - 1 - - 0 - - 11 - - 8 - - 0 - - 0 - - 11 - - 1 - - 2 - - 0 - - 200 - - 218 - - 7 - - 1 - - 57 - - 48 - - 0 - - 209 - - 160 - - 15 - - 1 - - 7 - data: - - 0 - - 1 - - 0 - - 0 - libs: [] -attachments: {} -signatures: {} diff --git a/tests/fixtures/attack_genesis_testnet.yaml b/tests/fixtures/attack_genesis_testnet.yaml deleted file mode 100644 index caf0a80..0000000 --- a/tests/fixtures/attack_genesis_testnet.yaml +++ /dev/null @@ -1,1149 +0,0 @@ -version: v2 -transfer: true -terminals: {} -genesis: - ffv: 0 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - flags: null - timestamp: 1728926035 - issuer: ssi:anonymous - testnet: false - altLayers1: [] - assetTags: - 4000: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - metadata: {} - globals: - 2000: - - 074e494154434b520e4e4941206173736574206e616d650002 - 2001: - - 09004e4941207465726d7300 - 2010: - - 9a02000000000000 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: 39f4d1888d1d994a2649397d34bfcaf8a9f7de2d6369dd1d42e0c61a26b4384b - vout: 1 - blinding: 7943510731595037200 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null -extensions: [] -bundles: -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: c269055b7750a234087c11acd7a408172cb84d8fc6af0ded42d8a8cbea6712e9:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 - - value: 99981200 - scriptPubkey: 0014ceb732c6400f984d3258c202811ef439234ff028 - - value: 0 - scriptPubkey: 6a20efce72c00a4dafa508d223854191b9bc534505d7b40841136ea57454bcd8f62e - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 4 - cofactor: 1 - path: - - 59fb64885c9d21d566c630261ebaf61e6fdfb90fd755734580e2853606e04468 - - 972bd31741970dcfdcb1fd6e1e0cb86b43a95cdf9be16e26b20f7efb55b8815a - - 59c4bea42d613b9b4d9190c70713db38fcb1213e1384390305c9f41b105e7ad7 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 93ff8f77c5f41ebdfb417b9f30a603e2b48a0db75d5a0e520495954e564f62f6 - knownTransitions: - 93ff8f77c5f41ebdfb417b9f30a603e2b48a0db75d5a0e520495954e564f62f6: - ffv: 0 - contractId: rgb:P9y8fj2n-Hjyhxbb-FSv9Jb6-xVz3qn$-laXX8N6-hzNhlHQ - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 76fc3455d84d793361211daa2a85be764b9bebc559dd2958833bf6ab153fa9a3 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 10355153668244730300 - state: - value: 50 - blinding: 6ba480e64c69b4e53fe7c76e5c79bb79e8d1a442ba405e9b568612b0014dc452 - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 1 - blinding: 4411272172758969930 - state: - value: 616 - blinding: 12d9fd983214c9993e96b7102204c30495acda3bc43e1fe327f86bce7d30ba2c - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: d84c37b6c6616184c454c815d970505bed9b3a3723a4445dd1289dc708bc80b3:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 - - value: 99971800 - scriptPubkey: 0014b63cbe65e66aaec213d9e25a2ff8cd4e4f3c47d0 - - value: 0 - scriptPubkey: 6a2036831c40589897909e67d439cba95004d53280635e2ca66b6e53da52551f957c - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 4 - cofactor: 1 - path: - - ade25d6370736e013b7148b4e223030112c4dff704d992e0a8d92073df669c2f - - f478b2c344da010822be93fb7405c56c0b95867ce56582a6c4f647b678fba56e - - 9461109d34187938798bf29433c2b3f11f08ed7f7c8831fcceeab43874f11689 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 295cbd02dbfeddee5c9691cfcc2b5c59b284c8130ad1c9e2cfb867b45dc24dec - knownTransitions: - 295cbd02dbfeddee5c9691cfcc2b5c59b284c8130ad1c9e2cfb867b45dc24dec: - ffv: 0 - contractId: rgb:P9y8fj2n-Hjyhxbb-FSv9Jb6-xVz3qn$-laXX8N6-hzNhlHQ - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 93ff8f77c5f41ebdfb417b9f30a603e2b48a0db75d5a0e520495954e564f62f6 - ty: 4000 - no: 1 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 5517491780835545414 - state: - value: 77 - blinding: ab9ad5d441db401474f2f15c2d7940cec37d8b1c962dc20752256f95fdfd1634 - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 1 - blinding: 17151752316201612509 - state: - value: 539 - blinding: 673f27c3f0398984c9a3c5b3f48b82348cde2c05dd58fe1795a55ac54f69e539 - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: 39f4d1888d1d994a2649397d34bfcaf8a9f7de2d6369dd1d42e0c61a26b4384b:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 - - value: 99990600 - scriptPubkey: 00147c22e5543af0a3dca1c89ae5ffbf6cadd03a1bb3 - - value: 0 - scriptPubkey: 6a209f6aed701fb9da0762a238d96e0b203220a609a9afaba47ea71ba96e08065458 - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 4 - cofactor: 1 - path: - - 09a4be7f9ba65f3e4588a93061fe429c8e257de6cb5194a82c1e4dc5d6ff48fd - - cdc9e7844302abff47462927f67cfc6b350a5023dcceb1798eeea250dcce7052 - - 6ef2b8c22960c49c7be94ea27b5909ac60dbbd69fe057d5475795a35802bf24a - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 76fc3455d84d793361211daa2a85be764b9bebc559dd2958833bf6ab153fa9a3 - knownTransitions: - 76fc3455d84d793361211daa2a85be764b9bebc559dd2958833bf6ab153fa9a3: - ffv: 0 - contractId: rgb:P9y8fj2n-Hjyhxbb-FSv9Jb6-xVz3qn$-laXX8N6-hzNhlHQ - nonce: 18446744073709551615 - transitionType: 65535 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 3fdcbc7e3da71e3ca1c5b6c54aff496fac55cf7aa7fe56975fc37a8733619474 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 1 - blinding: 16141698382146724670 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null - witness: null -schema: - ffv: 0 - flags: null - name: NonInflatableAsset - timestamp: 1713343888 - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - metaTypes: {} - globalTypes: - 2000: - reserved: null - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - maxItems: 1 - 2001: - reserved: null - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - maxItems: 1 - 2010: - reserved: null - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - maxItems: 1 - ownedTypes: - 4000: !fungible unsigned64Bit - valencyTypes: [] - genesis: - metadata: [] - globals: - 2000: once - 2001: once - 2010: once - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 9 - extensions: {} - transitions: - 10000: - metadata: [] - globals: {} - inputs: - 4000: onceOrMore - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 0 - reserved: null -ifaces: - ? version: v1 - name: RGB20Fixed - inherits: - - rgb:ifc:Vk9c4$Ny-Fv0J6tg-pDF05CE-312oCWh-fENNuia-GYbEu18#adios-alert-never - - rgb:ifc:13N6PRwT-T68!FGY-lBwX2cm-qesgJ11-j0nQkM1-WSCJFj4#ariel-gizmo-evita - - rgb:ifc:naFrAfgG-Kfu$A!c-3L!bC$4-s1LWJQV-4Iv!62u-4B3ab8Y#mailbox-dialog-iron - - rgb:ifc:w3Lk9Mt3-gKt$n5y-TYpVGg0-IDpK0p9-sHQ!hb6-m2Qr3a0#unicorn-reward-ladder - timestamp: 1711405444 - metadata: {} - globalState: - issuedSupply: - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - required: true - multiple: false - spec: - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - required: true - multiple: false - terms: - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - required: true - multiple: false - assignments: - assetOwner: - ownedState: amount - public: false - required: true - multiple: true - valencies: {} - genesis: - modifier: abstract - metadata: [] - globals: - issuedSupply: once - spec: once - terms: once - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - issuedMismatch - transitions: - transfer: - modifier: abstract - optional: false - metadata: [] - globals: {} - inputs: - assetOwner: onceOrMore - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - nonEqualAmounts - defaultAssignment: assetOwner - extensions: {} - defaultOperation: transfer - errors: - issuedMismatch: supply specified as a global parameter doesn't match the issued supply allocated to the asset owners - nonEqualAmounts: the sum of spent assets doesn't equal to the sum of assets in outputs - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - : version: v1 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - ifaceId: rgb:ifc:$iUnO9aO-1xhqUd6-1Jm5S5!-wM3ngby-5GVEylQ-ZTAMYDk#tornado-pioneer-bucket - timestamp: 1713343888 - metadata: [] - globalState: - - id: 2000 - name: spec - reserved: null - - id: 2001 - name: terms - reserved: null - - id: 2010 - name: issuedSupply - reserved: null - assignments: - - id: 4000 - name: assetOwner - reserved: null - valencies: [] - transitions: - - id: 10000 - name: transfer - reserved: null - extensions: [] - errors: - - id: 0 - name: nonEqualAmounts - reserved: null - - id: 1 - name: issuedMismatch - reserved: null - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w -supplements: [] -types: - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751: !List - - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355 - - min: 0 - max: 7 - 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01: !Tuple - - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154 - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042: !Primitive 64 - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb: !Tuple - - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90 - 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd: !Array - - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042 - - 32 - 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997 - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73: !Enum - - name: excl - tag: 33 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: amp - tag: 38 - - name: plus - tag: 43 - - name: dash - tag: 45 - - name: dot - tag: 46 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4: !Tuple - - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a: !Struct - - name: type - ty: b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660 - - name: digest - ty: 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd - 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7 - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8: !Enum - - name: space - tag: 32 - - name: excl - tag: 33 - - name: quotes - tag: 34 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: percent - tag: 37 - - name: ampersand - tag: 38 - - name: apostrophe - tag: 39 - - name: bracketL - tag: 40 - - name: bracketR - tag: 41 - - name: asterisk - tag: 42 - - name: plus - tag: 43 - - name: comma - tag: 44 - - name: minus - tag: 45 - - name: dot - tag: 46 - - name: slash - tag: 47 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: colon - tag: 58 - - name: semiColon - tag: 59 - - name: less - tag: 60 - - name: equal - tag: 61 - - name: greater - tag: 62 - - name: question - tag: 63 - - name: at - tag: 64 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: sqBracketL - tag: 91 - - name: backSlash - tag: 92 - - name: sqBracketR - tag: 93 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: backtick - tag: 96 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - - name: cBracketL - tag: 123 - - name: pipe - tag: 124 - - name: cBracketR - tag: 125 - - name: tilde - tag: 126 - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 0 - max: 65535 - 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa: !Tuple - - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f - 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7: !Struct - - name: text - ty: 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01 - - name: media - ty: e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81 - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f: !Primitive 8 - 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22: !Enum - - name: indivisible - tag: 0 - - name: deci - tag: 1 - - name: centi - tag: 2 - - name: milli - tag: 3 - - name: deciMilli - tag: 4 - - name: centiMilli - tag: 5 - - name: micro - tag: 6 - - name: deciMicro - tag: 7 - - name: centiMicro - tag: 8 - - name: nano - tag: 9 - - name: deciNano - tag: 10 - - name: centiNano - tag: 11 - - name: pico - tag: 12 - - name: deciPico - tag: 13 - - name: centiPico - tag: 14 - - name: femto - tag: 15 - - name: deciFemto - tag: 16 - - name: centiFemto - tag: 17 - - name: atto - tag: 18 - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f: !Tuple - - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2 - - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751 - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355: !Enum - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 1 - max: 255 - 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d: !Tuple - - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4 - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2: !Enum - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84: !Tuple - - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f - b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997: !Tuple - - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660: !Struct - - name: type - ty: 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - - name: subtype - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - - name: charset - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46: !List - - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73 - - min: 0 - max: 63 - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4: !Tuple - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc - caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7: !Tuple - - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4 - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90: !Tuple - - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1 - - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46 - d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01: !Struct - - name: ticker - ty: 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa - - name: name - ty: 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d - - name: details - ty: 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888 - - name: precision - ty: 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22 - d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c: !Primitive 0 - dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548: !Tuple - - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a - e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548 - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc: !List - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - min: 0 - max: 39 - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1: !Enum - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78: UnicodeChar -scripts: -- isae: - - ALU - - BPDIGEST - - RGB - code: - - 11 - - 0 - - 0 - - 0 - - 208 - - 160 - - 15 - - 1 - - 7 - - 11 - - 0 - - 1 - - 0 - - 11 - - 8 - - 0 - - 0 - - 11 - - 1 - - 2 - - 0 - - 200 - - 218 - - 7 - - 1 - - 57 - - 48 - - 0 - - 209 - - 160 - - 15 - - 1 - - 7 - data: - - 0 - - 1 - - 0 - - 0 - libs: [] -attachments: {} -signatures: {} diff --git a/tests/fixtures/attack_resolver_error.yaml b/tests/fixtures/attack_resolver_error.yaml deleted file mode 100644 index 00f696b..0000000 --- a/tests/fixtures/attack_resolver_error.yaml +++ /dev/null @@ -1,1127 +0,0 @@ -version: v2 -transfer: true -terminals: - 3bb2645029b3de98be6c3ed5ce3332b8591f59c693146a007b75db5cfdb7c7b8: - chain: bitcoin - data: e1c963ea4a2d4e21f870c713a76d0397a0cc197aece1f53a66ae9febf122bb50 -genesis: - ffv: 0 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - flags: null - timestamp: 1728925859 - issuer: ssi:anonymous - testnet: true - altLayers1: [] - assetTags: - 4000: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - metadata: {} - globals: - 2000: - - 074e494154434b520e4e4941206173736574206e616d650002 - 2001: - - 09004e4941207465726d7300 - 2010: - - 9a02000000000000 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: 22f0538e189f32922e55daf6fa0b7120bc01de8520a9a4c80655fdaf70272ac0 - vout: 1 - blinding: 7704601239148887312 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null -extensions: [] -bundles: -- pubWitness: - chain: bitcoin - data: !txid - d077ea7e3a55a215893a18e82cb03fda0f50619893e4aee0ba70b014e6d63248 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 0d4042fb3c309aa40bff3159cee3a0ca87c4efc804a5347aa1a363d7244a88f7 - - e56d0e3dbadefb489899917dbc2e1dbf0c49c3ff155e178ef52feab2f351fc7c - - 4edc7f8808488b46c10bedf910818a9afbe2512c1f08a436a7b3db244f22ac85 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3 - knownTransitions: - 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 10251942175724995735 - state: - value: 616 - blinding: 361c123b494b218e332794a2390dc6d5cc7c332f64cf8764b6dfb3e04e56c9fc - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - - seal: - chain: bitcoin - data: 108b3912eb0b836427f235bafe449f3153c2aae08887b948a3d8529f17b19b95 - state: - value: 50 - blinding: 48626c4335335cf04b56e9dc4570b7a8b2024b4f19aef719c79eca9e3027b482 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: 22f0538e189f32922e55daf6fa0b7120bc01de8520a9a4c80655fdaf70272ac0:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 99999600 - scriptPubkey: 00141d66111f9daca8769c3ab2b0fe14354b6198b29c - - value: 0 - scriptPubkey: 6a20a02ab7dd75b9911b540419440ebe8f5be0742f76fd9fdaf5e69ebb30f38d3f11 - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 0ae6caac7df078206a7af28b0a885098f743d49b92cdb3485558b804492a5be5 - - 843d661f6822486889697a7446a6a9bd1e123921c6dafdde687140cf863a9403 - - 040c8d2b550cc8f3bd210535dbf482f91e7fe62989168c1ed87eebf2b4f35be3 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e - knownTransitions: - fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 65535 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 260ba748cbd95421f871fcea5b5a8dca954ed9af5fed4613def3759a33bf11b8 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 7687739675014878388 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: d077ea7e3a55a215893a18e82cb03fda0f50619893e4aee0ba70b014e6d63248:0 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 99998800 - scriptPubkey: 00146ab6fe162c087a01a717d2b6d4bbef87829cec24 - - value: 0 - scriptPubkey: 6a2088b706bf16e225b5d438f48c8c1abc544e807bb7fb99e6fc8ca460d4de62d1b0 - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 91246094600e4cae70d42147330754f25ef710118c7bc3aa963b1a8900125b83 - - 58bb69c807310413032dd30a245738b48f1a5cb8645f55b8f089489ae16b0533 - - 500d82630b8bb4a1bcb8973500acae7114dc0d5ef77b748a60b4d93aa9375ca1 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: c04da8609a2a8ddf7e0e9847f4ebd6758b1091bceeda10094b24352c97840ea2 - knownTransitions: - c04da8609a2a8ddf7e0e9847f4ebd6758b1091bceeda10094b24352c97840ea2: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 9888072140771099372 - state: - value: 539 - blinding: ae89403cecbdb782ddba50b592d9590bb664bb3d4dc9f7772f7c6611f4755345 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - - seal: - chain: bitcoin - data: e1c963ea4a2d4e21f870c713a76d0397a0cc197aece1f53a66ae9febf122bb50 - state: - value: 77 - blinding: 8792d1fe5c8d6a0b556d43eca6346dc8d0c654d8c64e30294735ac5b2a17b7f8 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -schema: - ffv: 0 - flags: null - name: NonInflatableAsset - timestamp: 1713343888 - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - metaTypes: {} - globalTypes: - 2000: - reserved: null - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - maxItems: 1 - 2001: - reserved: null - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - maxItems: 1 - 2010: - reserved: null - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - maxItems: 1 - ownedTypes: - 4000: !fungible unsigned64Bit - valencyTypes: [] - genesis: - metadata: [] - globals: - 2000: once - 2001: once - 2010: once - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 9 - extensions: {} - transitions: - 10000: - metadata: [] - globals: {} - inputs: - 4000: onceOrMore - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 0 - reserved: null -ifaces: - ? version: v1 - name: RGB20Fixed - inherits: - - rgb:ifc:Vk9c4$Ny-Fv0J6tg-pDF05CE-312oCWh-fENNuia-GYbEu18#adios-alert-never - - rgb:ifc:13N6PRwT-T68!FGY-lBwX2cm-qesgJ11-j0nQkM1-WSCJFj4#ariel-gizmo-evita - - rgb:ifc:naFrAfgG-Kfu$A!c-3L!bC$4-s1LWJQV-4Iv!62u-4B3ab8Y#mailbox-dialog-iron - - rgb:ifc:w3Lk9Mt3-gKt$n5y-TYpVGg0-IDpK0p9-sHQ!hb6-m2Qr3a0#unicorn-reward-ladder - timestamp: 1711405444 - metadata: {} - globalState: - issuedSupply: - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - required: true - multiple: false - spec: - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - required: true - multiple: false - terms: - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - required: true - multiple: false - assignments: - assetOwner: - ownedState: amount - public: false - required: true - multiple: true - valencies: {} - genesis: - modifier: abstract - metadata: [] - globals: - issuedSupply: once - spec: once - terms: once - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - issuedMismatch - transitions: - transfer: - modifier: abstract - optional: false - metadata: [] - globals: {} - inputs: - assetOwner: onceOrMore - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - nonEqualAmounts - defaultAssignment: assetOwner - extensions: {} - defaultOperation: transfer - errors: - issuedMismatch: supply specified as a global parameter doesn't match the issued supply allocated to the asset owners - nonEqualAmounts: the sum of spent assets doesn't equal to the sum of assets in outputs - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - : version: v1 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - ifaceId: rgb:ifc:$iUnO9aO-1xhqUd6-1Jm5S5!-wM3ngby-5GVEylQ-ZTAMYDk#tornado-pioneer-bucket - timestamp: 1713343888 - metadata: [] - globalState: - - id: 2000 - name: spec - reserved: null - - id: 2001 - name: terms - reserved: null - - id: 2010 - name: issuedSupply - reserved: null - assignments: - - id: 4000 - name: assetOwner - reserved: null - valencies: [] - transitions: - - id: 10000 - name: transfer - reserved: null - extensions: [] - errors: - - id: 0 - name: nonEqualAmounts - reserved: null - - id: 1 - name: issuedMismatch - reserved: null - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w -supplements: [] -types: - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751: !List - - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355 - - min: 0 - max: 7 - 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01: !Tuple - - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154 - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042: !Primitive 64 - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb: !Tuple - - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90 - 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd: !Array - - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042 - - 32 - 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997 - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73: !Enum - - name: excl - tag: 33 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: amp - tag: 38 - - name: plus - tag: 43 - - name: dash - tag: 45 - - name: dot - tag: 46 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4: !Tuple - - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a: !Struct - - name: type - ty: b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660 - - name: digest - ty: 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd - 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7 - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8: !Enum - - name: space - tag: 32 - - name: excl - tag: 33 - - name: quotes - tag: 34 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: percent - tag: 37 - - name: ampersand - tag: 38 - - name: apostrophe - tag: 39 - - name: bracketL - tag: 40 - - name: bracketR - tag: 41 - - name: asterisk - tag: 42 - - name: plus - tag: 43 - - name: comma - tag: 44 - - name: minus - tag: 45 - - name: dot - tag: 46 - - name: slash - tag: 47 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: colon - tag: 58 - - name: semiColon - tag: 59 - - name: less - tag: 60 - - name: equal - tag: 61 - - name: greater - tag: 62 - - name: question - tag: 63 - - name: at - tag: 64 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: sqBracketL - tag: 91 - - name: backSlash - tag: 92 - - name: sqBracketR - tag: 93 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: backtick - tag: 96 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - - name: cBracketL - tag: 123 - - name: pipe - tag: 124 - - name: cBracketR - tag: 125 - - name: tilde - tag: 126 - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 0 - max: 65535 - 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa: !Tuple - - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f - 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7: !Struct - - name: text - ty: 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01 - - name: media - ty: e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81 - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f: !Primitive 8 - 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22: !Enum - - name: indivisible - tag: 0 - - name: deci - tag: 1 - - name: centi - tag: 2 - - name: milli - tag: 3 - - name: deciMilli - tag: 4 - - name: centiMilli - tag: 5 - - name: micro - tag: 6 - - name: deciMicro - tag: 7 - - name: centiMicro - tag: 8 - - name: nano - tag: 9 - - name: deciNano - tag: 10 - - name: centiNano - tag: 11 - - name: pico - tag: 12 - - name: deciPico - tag: 13 - - name: centiPico - tag: 14 - - name: femto - tag: 15 - - name: deciFemto - tag: 16 - - name: centiFemto - tag: 17 - - name: atto - tag: 18 - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f: !Tuple - - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2 - - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751 - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355: !Enum - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 1 - max: 255 - 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d: !Tuple - - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4 - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2: !Enum - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84: !Tuple - - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f - b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997: !Tuple - - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660: !Struct - - name: type - ty: 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - - name: subtype - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - - name: charset - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46: !List - - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73 - - min: 0 - max: 63 - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4: !Tuple - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc - caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7: !Tuple - - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4 - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90: !Tuple - - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1 - - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46 - d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01: !Struct - - name: ticker - ty: 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa - - name: name - ty: 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d - - name: details - ty: 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888 - - name: precision - ty: 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22 - d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c: !Primitive 0 - dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548: !Tuple - - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a - e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548 - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc: !List - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - min: 0 - max: 39 - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1: !Enum - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78: UnicodeChar -scripts: -- isae: - - ALU - - BPDIGEST - - RGB - code: - - 11 - - 0 - - 0 - - 0 - - 208 - - 160 - - 15 - - 1 - - 7 - - 11 - - 0 - - 1 - - 0 - - 11 - - 8 - - 0 - - 0 - - 11 - - 1 - - 2 - - 0 - - 200 - - 218 - - 7 - - 1 - - 57 - - 48 - - 0 - - 209 - - 160 - - 15 - - 1 - - 7 - data: - - 0 - - 1 - - 0 - - 0 - libs: [] -attachments: {} -signatures: {} diff --git a/tests/fixtures/bc_0bc3024ce6404cd7aea387debde687d9e8731228e16b04b4eefda7283069f1c3.yaml b/tests/fixtures/bc_0bc3024ce6404cd7aea387debde687d9e8731228e16b04b4eefda7283069f1c3.yaml deleted file mode 100644 index 4e1fb30..0000000 --- a/tests/fixtures/bc_0bc3024ce6404cd7aea387debde687d9e8731228e16b04b4eefda7283069f1c3.yaml +++ /dev/null @@ -1,16 +0,0 @@ -version: 2 -inputs: -- prevOutput: d84c37b6c6616184c454c815d970505bed9b3a3723a4445dd1289dc708bc80b3:1 - sigScript: '' - sequence: 0 - witness: - - 3044022031154900dd3db440c9d286fc6714ce73a63d3b70131fa61372dc830d63d8feb8022061376e25cc7e8850d0070d982092ecd1e715404b2185428a0950b24a410f98be01 - - 027884e03cdcf5f3ce603ff95bfa16d527d3078c7b48e31695a3d4ef6e552b175d -outputs: -- value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 -- value: 99971800 - scriptPubkey: 0014b63cbe65e66aaec213d9e25a2ff8cd4e4f3c47d0 -- value: 0 - scriptPubkey: 6a2036831c40589897909e67d439cba95004d53280635e2ca66b6e53da52551f957c -lockTime: 0 diff --git a/tests/fixtures/bc_3652d9fea802cb051f671455cbd7472e3bce2c440a4e54fa4321107037dfaff0.yaml b/tests/fixtures/bc_3652d9fea802cb051f671455cbd7472e3bce2c440a4e54fa4321107037dfaff0.yaml deleted file mode 100644 index e924c61..0000000 --- a/tests/fixtures/bc_3652d9fea802cb051f671455cbd7472e3bce2c440a4e54fa4321107037dfaff0.yaml +++ /dev/null @@ -1,14 +0,0 @@ -version: 2 -inputs: -- prevOutput: d077ea7e3a55a215893a18e82cb03fda0f50619893e4aee0ba70b014e6d63248:0 - sigScript: '' - sequence: 0 - witness: - - 3045022100980c27acde83d1583762873f8bb8b11ead3eb72831e0bb12b9f17b9445fc63fd0220528bb1fbe5ad8b0e7ab272e4648003f3ab235e24421e97d46adff70d280316c401 - - 02d40f2a8d89f52a92d1b2f1b1047bff2e00f6847dd4243a8adea0253cc3b94591 -outputs: -- value: 99998800 - scriptPubkey: 00146ab6fe162c087a01a717d2b6d4bbef87829cec24 -- value: 0 - scriptPubkey: 6a2088b706bf16e225b5d438f48c8c1abc544e807bb7fb99e6fc8ca460d4de62d1b0 -lockTime: 0 diff --git a/tests/fixtures/bc_a5c3085efe8dfdba0fa0e11d81bf90cdcac27c0af496c4de1a2fd9659948ffce.yaml b/tests/fixtures/bc_a5c3085efe8dfdba0fa0e11d81bf90cdcac27c0af496c4de1a2fd9659948ffce.yaml deleted file mode 100644 index ca5ff5c..0000000 --- a/tests/fixtures/bc_a5c3085efe8dfdba0fa0e11d81bf90cdcac27c0af496c4de1a2fd9659948ffce.yaml +++ /dev/null @@ -1,14 +0,0 @@ -version: 2 -inputs: -- prevOutput: 22f0538e189f32922e55daf6fa0b7120bc01de8520a9a4c80655fdaf70272ac0:1 - sigScript: '' - sequence: 0 - witness: - - 3044022017ded71ced861ea4e548ce9deeb69a556717911a644fb88369d12269cd25281302200cc72396108b905e8235362a953387f2195d51ea0376b0870cbfe90cbada9a9e01 - - 029376e491db9dde1d42ed68100e1bf069cf89a735d9175738f4238f9d617ed834 -outputs: -- value: 99999600 - scriptPubkey: 00141d66111f9daca8769c3ab2b0fe14354b6198b29c -- value: 0 - scriptPubkey: 6a20a02ab7dd75b9911b540419440ebe8f5be0742f76fd9fdaf5e69ebb30f38d3f11 -lockTime: 0 diff --git a/tests/fixtures/bc_c269055b7750a234087c11acd7a408172cb84d8fc6af0ded42d8a8cbea6712e9.yaml b/tests/fixtures/bc_c269055b7750a234087c11acd7a408172cb84d8fc6af0ded42d8a8cbea6712e9.yaml deleted file mode 100644 index 6ad6bc7..0000000 --- a/tests/fixtures/bc_c269055b7750a234087c11acd7a408172cb84d8fc6af0ded42d8a8cbea6712e9.yaml +++ /dev/null @@ -1,16 +0,0 @@ -version: 2 -inputs: -- prevOutput: 39f4d1888d1d994a2649397d34bfcaf8a9f7de2d6369dd1d42e0c61a26b4384b:1 - sigScript: '' - sequence: 0 - witness: - - 3044022040589e75b92bd9a9cb725edbbb06d7fe5ee24432f94f758e36dd929841e3701d02206c83c8d7673ee10c9deef90aaad3b71587484cda6ade3eae51e44f32430cb0db01 - - 023b7da09b05da276d729b004663767db536967bc782d14b3d87baba73f1e7de94 -outputs: -- value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 -- value: 99990600 - scriptPubkey: 00147c22e5543af0a3dca1c89ae5ffbf6cadd03a1bb3 -- value: 0 - scriptPubkey: 6a209f6aed701fb9da0762a238d96e0b203220a609a9afaba47ea71ba96e08065458 -lockTime: 0 diff --git a/tests/fixtures/bc_d077ea7e3a55a215893a18e82cb03fda0f50619893e4aee0ba70b014e6d63248.yaml b/tests/fixtures/bc_d077ea7e3a55a215893a18e82cb03fda0f50619893e4aee0ba70b014e6d63248.yaml deleted file mode 100644 index 9d770ae..0000000 --- a/tests/fixtures/bc_d077ea7e3a55a215893a18e82cb03fda0f50619893e4aee0ba70b014e6d63248.yaml +++ /dev/null @@ -1,14 +0,0 @@ -version: 2 -inputs: -- prevOutput: a5c3085efe8dfdba0fa0e11d81bf90cdcac27c0af496c4de1a2fd9659948ffce:0 - sigScript: '' - sequence: 0 - witness: - - 30450221008ed3d3ce756c894485a9bf761add8cd58dfe5a3ee844226b8d09db9760e32a800220678c467e6923976550ce485ebbac7861dcfa2193c18d687c8b25863ad6331f7b01 - - 030508210e85f58443ad57f66f75dacc76ab84fca7879f10a7325eeeef942e3e84 -outputs: -- value: 99999200 - scriptPubkey: 001430d944c2d49db5c315c49e13aab8cad8b9415cac -- value: 0 - scriptPubkey: 6a20669e87f4fe2acf39e58ef94c4a2f81791b7848acac344cd8a2e562f4777acc7f -lockTime: 0 diff --git a/tests/fixtures/bc_d84c37b6c6616184c454c815d970505bed9b3a3723a4445dd1289dc708bc80b3.yaml b/tests/fixtures/bc_d84c37b6c6616184c454c815d970505bed9b3a3723a4445dd1289dc708bc80b3.yaml deleted file mode 100644 index bed65f8..0000000 --- a/tests/fixtures/bc_d84c37b6c6616184c454c815d970505bed9b3a3723a4445dd1289dc708bc80b3.yaml +++ /dev/null @@ -1,16 +0,0 @@ -version: 2 -inputs: -- prevOutput: c269055b7750a234087c11acd7a408172cb84d8fc6af0ded42d8a8cbea6712e9:1 - sigScript: '' - sequence: 0 - witness: - - 3044022073070da9946fab45dbc02010cacc6e3e89c0539e1741c8abadb1e9aaa7831b190220561c8270ce63fe44af34624a0aa93f6c1fa28cec14f39d92c16e205fe6e1778401 - - 020e8dd627ba520d0c209b7859c1e7cbe4d01bd609d0a28dbcd9be2583692786a0 -outputs: -- value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 -- value: 99981200 - scriptPubkey: 0014ceb732c6400f984d3258c202811ef439234ff028 -- value: 0 - scriptPubkey: 6a20efce72c00a4dafa508d223854191b9bc534505d7b40841136ea57454bcd8f62e -lockTime: 0 diff --git a/tests/fixtures/consignment_A.yaml b/tests/fixtures/consignment_A.yaml deleted file mode 100644 index bbda5fe..0000000 --- a/tests/fixtures/consignment_A.yaml +++ /dev/null @@ -1,1138 +0,0 @@ -version: v2 -transfer: true -terminals: - 3bb2645029b3de98be6c3ed5ce3332b8591f59c693146a007b75db5cfdb7c7b8: - chain: bitcoin - data: e1c963ea4a2d4e21f870c713a76d0397a0cc197aece1f53a66ae9febf122bb50 -genesis: - ffv: 0 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - flags: null - timestamp: 1728925859 - issuer: ssi:anonymous - testnet: true - altLayers1: [] - assetTags: - 4000: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - metadata: {} - globals: - 2000: - - 074e494154434b520e4e4941206173736574206e616d650002 - 2001: - - 09004e4941207465726d7300 - 2010: - - 9a02000000000000 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: 22f0538e189f32922e55daf6fa0b7120bc01de8520a9a4c80655fdaf70272ac0 - vout: 1 - blinding: 7704601239148887312 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null -extensions: [] -bundles: -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: a5c3085efe8dfdba0fa0e11d81bf90cdcac27c0af496c4de1a2fd9659948ffce:0 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 99999200 - scriptPubkey: 001430d944c2d49db5c315c49e13aab8cad8b9415cac - - value: 0 - scriptPubkey: 6a20669e87f4fe2acf39e58ef94c4a2f81791b7848acac344cd8a2e562f4777acc7f - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 0d4042fb3c309aa40bff3159cee3a0ca87c4efc804a5347aa1a363d7244a88f7 - - e56d0e3dbadefb489899917dbc2e1dbf0c49c3ff155e178ef52feab2f351fc7c - - 4edc7f8808488b46c10bedf910818a9afbe2512c1f08a436a7b3db244f22ac85 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3 - knownTransitions: - 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 10251942175724995735 - state: - value: 616 - blinding: 361c123b494b218e332794a2390dc6d5cc7c332f64cf8764b6dfb3e04e56c9fc - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - - seal: - chain: bitcoin - data: 108b3912eb0b836427f235bafe449f3153c2aae08887b948a3d8529f17b19b95 - state: - value: 50 - blinding: 48626c4335335cf04b56e9dc4570b7a8b2024b4f19aef719c79eca9e3027b482 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: 22f0538e189f32922e55daf6fa0b7120bc01de8520a9a4c80655fdaf70272ac0:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 99999600 - scriptPubkey: 00141d66111f9daca8769c3ab2b0fe14354b6198b29c - - value: 0 - scriptPubkey: 6a20a02ab7dd75b9911b540419440ebe8f5be0742f76fd9fdaf5e69ebb30f38d3f11 - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 0ae6caac7df078206a7af28b0a885098f743d49b92cdb3485558b804492a5be5 - - 843d661f6822486889697a7446a6a9bd1e123921c6dafdde687140cf863a9403 - - 040c8d2b550cc8f3bd210535dbf482f91e7fe62989168c1ed87eebf2b4f35be3 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e - knownTransitions: - fb58c747eec9c44a05ec907ec9d14e0e72572f75db0a3f9aa47f0673702e760e: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 65535 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 260ba748cbd95421f871fcea5b5a8dca954ed9af5fed4613def3759a33bf11b8 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 7687739675014878388 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: d077ea7e3a55a215893a18e82cb03fda0f50619893e4aee0ba70b014e6d63248:0 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 99998800 - scriptPubkey: 00146ab6fe162c087a01a717d2b6d4bbef87829cec24 - - value: 0 - scriptPubkey: 6a2088b706bf16e225b5d438f48c8c1abc544e807bb7fb99e6fc8ca460d4de62d1b0 - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 1 - cofactor: 1 - path: - - 91246094600e4cae70d42147330754f25ef710118c7bc3aa963b1a8900125b83 - - 58bb69c807310413032dd30a245738b48f1a5cb8645f55b8f089489ae16b0533 - - 500d82630b8bb4a1bcb8973500acae7114dc0d5ef77b748a60b4d93aa9375ca1 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: c04da8609a2a8ddf7e0e9847f4ebd6758b1091bceeda10094b24352c97840ea2 - knownTransitions: - c04da8609a2a8ddf7e0e9847f4ebd6758b1091bceeda10094b24352c97840ea2: - ffv: 0 - contractId: rgb:JgunSMvZ-VCH4cfz-qW1qNyp-VO2a9f7-UYT3vN1-mjO$Ebg - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 9b50df314989fe006013a96d2ded4b508e5f32ef2b29e7245abfb3d9a35888e3 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 9888072140771099372 - state: - value: 539 - blinding: ae89403cecbdb782ddba50b592d9590bb664bb3d4dc9f7772f7c6611f4755345 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - - seal: - chain: bitcoin - data: e1c963ea4a2d4e21f870c713a76d0397a0cc197aece1f53a66ae9febf122bb50 - state: - value: 77 - blinding: 8792d1fe5c8d6a0b556d43eca6346dc8d0c654d8c64e30294735ac5b2a17b7f8 - tag: 603a2b302aac8d1cd7c8adc3acd72f31ce652128f96218fa5b519fd5e9930f6d - lock: null - valencies: [] - validator: null - witness: null -schema: - ffv: 0 - flags: null - name: NonInflatableAsset - timestamp: 1713343888 - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - metaTypes: {} - globalTypes: - 2000: - reserved: null - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - maxItems: 1 - 2001: - reserved: null - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - maxItems: 1 - 2010: - reserved: null - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - maxItems: 1 - ownedTypes: - 4000: !fungible unsigned64Bit - valencyTypes: [] - genesis: - metadata: [] - globals: - 2000: once - 2001: once - 2010: once - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 9 - extensions: {} - transitions: - 10000: - metadata: [] - globals: {} - inputs: - 4000: onceOrMore - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 0 - reserved: null -ifaces: - ? version: v1 - name: RGB20Fixed - inherits: - - rgb:ifc:Vk9c4$Ny-Fv0J6tg-pDF05CE-312oCWh-fENNuia-GYbEu18#adios-alert-never - - rgb:ifc:13N6PRwT-T68!FGY-lBwX2cm-qesgJ11-j0nQkM1-WSCJFj4#ariel-gizmo-evita - - rgb:ifc:naFrAfgG-Kfu$A!c-3L!bC$4-s1LWJQV-4Iv!62u-4B3ab8Y#mailbox-dialog-iron - - rgb:ifc:w3Lk9Mt3-gKt$n5y-TYpVGg0-IDpK0p9-sHQ!hb6-m2Qr3a0#unicorn-reward-ladder - timestamp: 1711405444 - metadata: {} - globalState: - issuedSupply: - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - required: true - multiple: false - spec: - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - required: true - multiple: false - terms: - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - required: true - multiple: false - assignments: - assetOwner: - ownedState: amount - public: false - required: true - multiple: true - valencies: {} - genesis: - modifier: abstract - metadata: [] - globals: - issuedSupply: once - spec: once - terms: once - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - issuedMismatch - transitions: - transfer: - modifier: abstract - optional: false - metadata: [] - globals: {} - inputs: - assetOwner: onceOrMore - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - nonEqualAmounts - defaultAssignment: assetOwner - extensions: {} - defaultOperation: transfer - errors: - issuedMismatch: supply specified as a global parameter doesn't match the issued supply allocated to the asset owners - nonEqualAmounts: the sum of spent assets doesn't equal to the sum of assets in outputs - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - : version: v1 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - ifaceId: rgb:ifc:$iUnO9aO-1xhqUd6-1Jm5S5!-wM3ngby-5GVEylQ-ZTAMYDk#tornado-pioneer-bucket - timestamp: 1713343888 - metadata: [] - globalState: - - id: 2000 - name: spec - reserved: null - - id: 2001 - name: terms - reserved: null - - id: 2010 - name: issuedSupply - reserved: null - assignments: - - id: 4000 - name: assetOwner - reserved: null - valencies: [] - transitions: - - id: 10000 - name: transfer - reserved: null - extensions: [] - errors: - - id: 0 - name: nonEqualAmounts - reserved: null - - id: 1 - name: issuedMismatch - reserved: null - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w -supplements: [] -types: - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751: !List - - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355 - - min: 0 - max: 7 - 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01: !Tuple - - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154 - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042: !Primitive 64 - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb: !Tuple - - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90 - 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd: !Array - - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042 - - 32 - 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997 - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73: !Enum - - name: excl - tag: 33 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: amp - tag: 38 - - name: plus - tag: 43 - - name: dash - tag: 45 - - name: dot - tag: 46 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4: !Tuple - - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a: !Struct - - name: type - ty: b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660 - - name: digest - ty: 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd - 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7 - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8: !Enum - - name: space - tag: 32 - - name: excl - tag: 33 - - name: quotes - tag: 34 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: percent - tag: 37 - - name: ampersand - tag: 38 - - name: apostrophe - tag: 39 - - name: bracketL - tag: 40 - - name: bracketR - tag: 41 - - name: asterisk - tag: 42 - - name: plus - tag: 43 - - name: comma - tag: 44 - - name: minus - tag: 45 - - name: dot - tag: 46 - - name: slash - tag: 47 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: colon - tag: 58 - - name: semiColon - tag: 59 - - name: less - tag: 60 - - name: equal - tag: 61 - - name: greater - tag: 62 - - name: question - tag: 63 - - name: at - tag: 64 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: sqBracketL - tag: 91 - - name: backSlash - tag: 92 - - name: sqBracketR - tag: 93 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: backtick - tag: 96 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - - name: cBracketL - tag: 123 - - name: pipe - tag: 124 - - name: cBracketR - tag: 125 - - name: tilde - tag: 126 - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 0 - max: 65535 - 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa: !Tuple - - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f - 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7: !Struct - - name: text - ty: 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01 - - name: media - ty: e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81 - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f: !Primitive 8 - 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22: !Enum - - name: indivisible - tag: 0 - - name: deci - tag: 1 - - name: centi - tag: 2 - - name: milli - tag: 3 - - name: deciMilli - tag: 4 - - name: centiMilli - tag: 5 - - name: micro - tag: 6 - - name: deciMicro - tag: 7 - - name: centiMicro - tag: 8 - - name: nano - tag: 9 - - name: deciNano - tag: 10 - - name: centiNano - tag: 11 - - name: pico - tag: 12 - - name: deciPico - tag: 13 - - name: centiPico - tag: 14 - - name: femto - tag: 15 - - name: deciFemto - tag: 16 - - name: centiFemto - tag: 17 - - name: atto - tag: 18 - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f: !Tuple - - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2 - - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751 - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355: !Enum - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 1 - max: 255 - 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d: !Tuple - - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4 - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2: !Enum - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84: !Tuple - - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f - b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997: !Tuple - - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660: !Struct - - name: type - ty: 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - - name: subtype - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - - name: charset - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46: !List - - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73 - - min: 0 - max: 63 - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4: !Tuple - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc - caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7: !Tuple - - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4 - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90: !Tuple - - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1 - - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46 - d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01: !Struct - - name: ticker - ty: 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa - - name: name - ty: 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d - - name: details - ty: 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888 - - name: precision - ty: 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22 - d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c: !Primitive 0 - dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548: !Tuple - - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a - e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548 - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc: !List - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - min: 0 - max: 39 - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1: !Enum - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78: UnicodeChar -scripts: -- isae: - - ALU - - BPDIGEST - - RGB - code: - - 11 - - 0 - - 0 - - 0 - - 208 - - 160 - - 15 - - 1 - - 7 - - 11 - - 0 - - 1 - - 0 - - 11 - - 8 - - 0 - - 0 - - 11 - - 1 - - 2 - - 0 - - 200 - - 218 - - 7 - - 1 - - 57 - - 48 - - 0 - - 209 - - 160 - - 15 - - 1 - - 7 - data: - - 0 - - 1 - - 0 - - 0 - libs: [] -attachments: {} -signatures: {} diff --git a/tests/fixtures/consignment_B.yaml b/tests/fixtures/consignment_B.yaml deleted file mode 100644 index bd61796..0000000 --- a/tests/fixtures/consignment_B.yaml +++ /dev/null @@ -1,1149 +0,0 @@ -version: v2 -transfer: true -terminals: {} -genesis: - ffv: 0 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - flags: null - timestamp: 1728926035 - issuer: ssi:anonymous - testnet: true - altLayers1: [] - assetTags: - 4000: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - metadata: {} - globals: - 2000: - - 074e494154434b520e4e4941206173736574206e616d650002 - 2001: - - 09004e4941207465726d7300 - 2010: - - 9a02000000000000 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: 39f4d1888d1d994a2649397d34bfcaf8a9f7de2d6369dd1d42e0c61a26b4384b - vout: 1 - blinding: 7943510731595037200 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null -extensions: [] -bundles: -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: c269055b7750a234087c11acd7a408172cb84d8fc6af0ded42d8a8cbea6712e9:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 - - value: 99981200 - scriptPubkey: 0014ceb732c6400f984d3258c202811ef439234ff028 - - value: 0 - scriptPubkey: 6a20efce72c00a4dafa508d223854191b9bc534505d7b40841136ea57454bcd8f62e - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 4 - cofactor: 1 - path: - - 59fb64885c9d21d566c630261ebaf61e6fdfb90fd755734580e2853606e04468 - - 972bd31741970dcfdcb1fd6e1e0cb86b43a95cdf9be16e26b20f7efb55b8815a - - 59c4bea42d613b9b4d9190c70713db38fcb1213e1384390305c9f41b105e7ad7 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 93ff8f77c5f41ebdfb417b9f30a603e2b48a0db75d5a0e520495954e564f62f6 - knownTransitions: - 93ff8f77c5f41ebdfb417b9f30a603e2b48a0db75d5a0e520495954e564f62f6: - ffv: 0 - contractId: rgb:P9y8fj2n-Hjyhxbb-FSv9Jb6-xVz3qn$-laXX8N6-hzNhlHQ - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 76fc3455d84d793361211daa2a85be764b9bebc559dd2958833bf6ab153fa9a3 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 10355153668244730300 - state: - value: 50 - blinding: 6ba480e64c69b4e53fe7c76e5c79bb79e8d1a442ba405e9b568612b0014dc452 - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 1 - blinding: 4411272172758969930 - state: - value: 616 - blinding: 12d9fd983214c9993e96b7102204c30495acda3bc43e1fe327f86bce7d30ba2c - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: d84c37b6c6616184c454c815d970505bed9b3a3723a4445dd1289dc708bc80b3:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 - - value: 99971800 - scriptPubkey: 0014b63cbe65e66aaec213d9e25a2ff8cd4e4f3c47d0 - - value: 0 - scriptPubkey: 6a2036831c40589897909e67d439cba95004d53280635e2ca66b6e53da52551f957c - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 4 - cofactor: 1 - path: - - ade25d6370736e013b7148b4e223030112c4dff704d992e0a8d92073df669c2f - - f478b2c344da010822be93fb7405c56c0b95867ce56582a6c4f647b678fba56e - - 9461109d34187938798bf29433c2b3f11f08ed7f7c8831fcceeab43874f11689 - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 295cbd02dbfeddee5c9691cfcc2b5c59b284c8130ad1c9e2cfb867b45dc24dec - knownTransitions: - 295cbd02dbfeddee5c9691cfcc2b5c59b284c8130ad1c9e2cfb867b45dc24dec: - ffv: 0 - contractId: rgb:P9y8fj2n-Hjyhxbb-FSv9Jb6-xVz3qn$-laXX8N6-hzNhlHQ - nonce: 18446744073709551615 - transitionType: 10000 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 93ff8f77c5f41ebdfb417b9f30a603e2b48a0db75d5a0e520495954e564f62f6 - ty: 4000 - no: 1 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 0 - blinding: 5517491780835545414 - state: - value: 77 - blinding: ab9ad5d441db401474f2f15c2d7940cec37d8b1c962dc20752256f95fdfd1634 - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 1 - blinding: 17151752316201612509 - state: - value: 539 - blinding: 673f27c3f0398984c9a3c5b3f48b82348cde2c05dd58fe1795a55ac54f69e539 - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null - witness: null -- pubWitness: - chain: bitcoin - data: !tx - version: 2 - inputs: - - prevOutput: 39f4d1888d1d994a2649397d34bfcaf8a9f7de2d6369dd1d42e0c61a26b4384b:1 - sigScript: '' - sequence: 0 - witness: [] - outputs: - - value: 9000 - scriptPubkey: 0014a39902b742ace887eeef8b91463f30893f777a12 - - value: 99990600 - scriptPubkey: 00147c22e5543af0a3dca1c89ae5ffbf6cadd03a1bb3 - - value: 0 - scriptPubkey: 6a209f6aed701fb9da0762a238d96e0b203220a609a9afaba47ea71ba96e08065458 - lockTime: 0 - anchoredBundles: !opret - mpcProof: - pos: 4 - cofactor: 1 - path: - - 09a4be7f9ba65f3e4588a93061fe429c8e257de6cb5194a82c1e4dc5d6ff48fd - - cdc9e7844302abff47462927f67cfc6b350a5023dcceb1798eeea250dcce7052 - - 6ef2b8c22960c49c7be94ea27b5909ac60dbbd69fe057d5475795a35802bf24a - dbcProof: null - bundle: - closeMethod: opretFirst - inputMap: - 0: 76fc3455d84d793361211daa2a85be764b9bebc559dd2958833bf6ab153fa9a3 - knownTransitions: - 76fc3455d84d793361211daa2a85be764b9bebc559dd2958833bf6ab153fa9a3: - ffv: 0 - contractId: rgb:P9y8fj2n-Hjyhxbb-FSv9Jb6-xVz3qn$-laXX8N6-hzNhlHQ - nonce: 18446744073709551615 - transitionType: 65535 - metadata: {} - globals: {} - inputs: - - prevOut: - op: 3fdcbc7e3da71e3ca1c5b6c54aff496fac55cf7aa7fe56975fc37a8733619474 - ty: 4000 - no: 0 - assignments: - 4000: - type: fungible - items: - - seal: - chain: bitcoin - data: - method: opretFirst - txid: null - vout: 1 - blinding: 16141698382146724670 - state: - value: 666 - blinding: 7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e - tag: 182bcffc792b3b0b5ea98515b0babbf1650db23f30e508eb8637000d8ad590db - lock: null - valencies: [] - validator: null - witness: null -schema: - ffv: 0 - flags: null - name: NonInflatableAsset - timestamp: 1713343888 - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - metaTypes: {} - globalTypes: - 2000: - reserved: null - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - maxItems: 1 - 2001: - reserved: null - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - maxItems: 1 - 2010: - reserved: null - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - maxItems: 1 - ownedTypes: - 4000: !fungible unsigned64Bit - valencyTypes: [] - genesis: - metadata: [] - globals: - 2000: once - 2001: once - 2010: once - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 9 - extensions: {} - transitions: - 10000: - metadata: [] - globals: {} - inputs: - 4000: onceOrMore - assignments: - 4000: onceOrMore - valencies: [] - validator: - lib: abf099d28bed50df5e065715327f3a9b329f777cb0b9fefff634c193a03cb626 - pos: 0 - reserved: null -ifaces: - ? version: v1 - name: RGB20Fixed - inherits: - - rgb:ifc:Vk9c4$Ny-Fv0J6tg-pDF05CE-312oCWh-fENNuia-GYbEu18#adios-alert-never - - rgb:ifc:13N6PRwT-T68!FGY-lBwX2cm-qesgJ11-j0nQkM1-WSCJFj4#ariel-gizmo-evita - - rgb:ifc:naFrAfgG-Kfu$A!c-3L!bC$4-s1LWJQV-4Iv!62u-4B3ab8Y#mailbox-dialog-iron - - rgb:ifc:w3Lk9Mt3-gKt$n5y-TYpVGg0-IDpK0p9-sHQ!hb6-m2Qr3a0#unicorn-reward-ladder - timestamp: 1711405444 - metadata: {} - globalState: - issuedSupply: - semId: 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84 - required: true - multiple: false - spec: - semId: d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01 - required: true - multiple: false - terms: - semId: 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7 - required: true - multiple: false - assignments: - assetOwner: - ownedState: amount - public: false - required: true - multiple: true - valencies: {} - genesis: - modifier: abstract - metadata: [] - globals: - issuedSupply: once - spec: once - terms: once - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - issuedMismatch - transitions: - transfer: - modifier: abstract - optional: false - metadata: [] - globals: {} - inputs: - assetOwner: onceOrMore - assignments: - assetOwner: onceOrMore - valencies: [] - errors: - - nonEqualAmounts - defaultAssignment: assetOwner - extensions: {} - defaultOperation: transfer - errors: - issuedMismatch: supply specified as a global parameter doesn't match the issued supply allocated to the asset owners - nonEqualAmounts: the sum of spent assets doesn't equal to the sum of assets in outputs - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w - : version: v1 - schemaId: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana - ifaceId: rgb:ifc:$iUnO9aO-1xhqUd6-1Jm5S5!-wM3ngby-5GVEylQ-ZTAMYDk#tornado-pioneer-bucket - timestamp: 1713343888 - metadata: [] - globalState: - - id: 2000 - name: spec - reserved: null - - id: 2001 - name: terms - reserved: null - - id: 2010 - name: issuedSupply - reserved: null - assignments: - - id: 4000 - name: assetOwner - reserved: null - valencies: [] - transitions: - - id: 10000 - name: transfer - reserved: null - extensions: [] - errors: - - id: 0 - name: nonEqualAmounts - reserved: null - - id: 1 - name: issuedMismatch - reserved: null - developer: ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w -supplements: [] -types: - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751: !List - - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355 - - min: 0 - max: 7 - 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01: !Tuple - - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154 - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042: !Primitive 64 - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb: !Tuple - - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90 - 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd: !Array - - 1cabbfc3d826c0bfd1e9770a889efacc8b6716ad014a3eec10b6591530229042 - - 32 - 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997 - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73: !Enum - - name: excl - tag: 33 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: amp - tag: 38 - - name: plus - tag: 43 - - name: dash - tag: 45 - - name: dot - tag: 46 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4: !Tuple - - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a: !Struct - - name: type - ty: b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660 - - name: digest - ty: 2a5baaac5089ff098d150b482cfed8bcd01a91c0d7b45d32216ed576ab71ebdd - 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7 - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8: !Enum - - name: space - tag: 32 - - name: excl - tag: 33 - - name: quotes - tag: 34 - - name: hash - tag: 35 - - name: dollar - tag: 36 - - name: percent - tag: 37 - - name: ampersand - tag: 38 - - name: apostrophe - tag: 39 - - name: bracketL - tag: 40 - - name: bracketR - tag: 41 - - name: asterisk - tag: 42 - - name: plus - tag: 43 - - name: comma - tag: 44 - - name: minus - tag: 45 - - name: dot - tag: 46 - - name: slash - tag: 47 - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: colon - tag: 58 - - name: semiColon - tag: 59 - - name: less - tag: 60 - - name: equal - tag: 61 - - name: greater - tag: 62 - - name: question - tag: 63 - - name: at - tag: 64 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: sqBracketL - tag: 91 - - name: backSlash - tag: 92 - - name: sqBracketR - tag: 93 - - name: caret - tag: 94 - - name: lodash - tag: 95 - - name: backtick - tag: 96 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - - name: cBracketL - tag: 123 - - name: pipe - tag: 124 - - name: cBracketR - tag: 125 - - name: tilde - tag: 126 - 560d96f7a47924b2c3df040e6463398fd65fd591652c294342bfa5f939155154: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 0 - max: 65535 - 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa: !Tuple - - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f - 5b8bc7543832054a1d22be94226be7538b133a26881cba4613027878e05c6cf7: !Struct - - name: text - ty: 18cb946f1293cf180e9d78dcc65bc59b472ffffeadfbf58db198cc8328f64b01 - - name: media - ty: e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81 - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f: !Primitive 8 - 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22: !Enum - - name: indivisible - tag: 0 - - name: deci - tag: 1 - - name: centi - tag: 2 - - name: milli - tag: 3 - - name: deciMilli - tag: 4 - - name: centiMilli - tag: 5 - - name: micro - tag: 6 - - name: deciMicro - tag: 7 - - name: centiMicro - tag: 8 - - name: nano - tag: 9 - - name: deciNano - tag: 10 - - name: centiNano - tag: 11 - - name: pico - tag: 12 - - name: deciPico - tag: 13 - - name: centiPico - tag: 14 - - name: femto - tag: 15 - - name: deciFemto - tag: 16 - - name: centiFemto - tag: 17 - - name: atto - tag: 18 - 5e5ec8924f73cd72c4225c96ab47796658ef1b729ca306e260bca42b25891d0f: !Tuple - - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2 - - 0af65fd62581de85cbd14e23e2db9a92bbef8b7974ffe1b50c4c74db8f86e751 - 5f5e26e5c5053c1b4544515bc6a0653da02a0791fb31116d71a4fad916e15355: !Enum - - name: zero - tag: 48 - - name: one - tag: 49 - - name: two - tag: 50 - - name: three - tag: 51 - - name: four - tag: 52 - - name: five - tag: 53 - - name: six - tag: 54 - - name: seven - tag: 55 - - name: eight - tag: 56 - - name: nine - tag: 57 - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 63aa2314e8b147c8b284dfb39a9e10d19caad5faea848e3cb9849d9167d6344a: !List - - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78 - - min: 1 - max: 255 - 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d: !Tuple - - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4 - 822380f475f0edb4b5dc517991de7390ada2dbb3752c4c066851aa01630296c2: !Enum - - name: _A - tag: 65 - - name: _B - tag: 66 - - name: _C - tag: 67 - - name: _D - tag: 68 - - name: _E - tag: 69 - - name: _F - tag: 70 - - name: _G - tag: 71 - - name: _H - tag: 72 - - name: _I - tag: 73 - - name: _J - tag: 74 - - name: _K - tag: 75 - - name: _L - tag: 76 - - name: _M - tag: 77 - - name: _N - tag: 78 - - name: _O - tag: 79 - - name: _P - tag: 80 - - name: _Q - tag: 81 - - name: _R - tag: 82 - - name: _S - tag: 83 - - name: _T - tag: 84 - - name: _U - tag: 85 - - name: _V - tag: 86 - - name: _W - tag: 87 - - name: _X - tag: 88 - - name: _Y - tag: 89 - - name: _Z - tag: 90 - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - 888c5865633af13b95b7cd1a8d8af2dac1dc140b977251d9d4daf3c7511c8e84: !Tuple - - 5ca149585de534ee91b3e3a030b7efd4cdb79abea9152f101f3759b4c7210e1f - b070d38ff6d20c5ae5d80715ca31541d5a52bbdecbd3529d38e6ddb672200997: !Tuple - - 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - b10ddefe8020add8a0ca08292150abb13c514d76de5168c1c97105a27e676660: !Struct - - name: type - ty: 1cb0758e14c2008c0f008ce6d2d41e9e1937e1cd0f9914c59a7e29e1ce7ba0bb - - name: subtype - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - - name: charset - ty: 2fd8f27a172712903e6a3e96f0f85c0480b4211a17acd13059fc51d4a4bbde2c - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46: !List - - 3cd1a29dccad9b917b26305f89a8a4fb2118302a4e73c5ac0a780de6ab005e73 - - min: 0 - max: 63 - c43a7d9eb9b3027973c98f5dd6e1ac04f5cbd34240c0bebc0a0fb808140094d4: !Tuple - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc - caff8faeb38a00a04e3621538f8e61d75a85a465cb0a0e48c3593e7eaa6c5fc7: !Tuple - - 3f2b72b7c4af1a630cb6d3ff088baf351093ee465b9e7d472a610082e449d7e4 - ccc272928f793803d91f5dad8d51cc986b4332380f9224f7c7c1514d768ebb90: !Tuple - - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1 - - bf8fcbe9c5395731a6b4cd61fb00dfe7a5d629365339c55aeae087a3b90aaa46 - d7fcbee31ef0a85d5f973bda1b0b8c9e7efbcbc5572577382cacd3bdb4218a01: !Struct - - name: ticker - ty: 5b772c8eb15fd74700c79241f60f8fda37e736b3fd462ab017ce4d454efa81aa - - name: name - ty: 805ec5bc5312c84190445da16aa1c08a09e300e8323acfae6a23420a29ad003d - - name: details - ty: 45b780258601c526b23b5b4861460a9050e13f35fbbe8305a8001157e4013888 - - name: precision - ty: 5d03c4178da98e7e3f3af343e3997d74201d11f42732cfbea2b04b8e3ff15f22 - d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c: !Primitive 0 - dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548: !Tuple - - 43aa7fc5f6f5644fe5a2ae5e1aa99042cdeb879442e34c723ff5827fb133de8a - e087a83496338799afc48a9211683a427d2bd33e2ea7ebb8a8b880ea4ab4eb81: !Union - ? name: none - tag: 0 - : d83fbee02f0de5b46cf80fe11ef7fdf061c78d975d31ade9eea2bc4099339e6c - ? name: some - tag: 1 - : dc1e2f52567f725fd730ad84867f0da4c9ba9af0813311dfe4ef3e3c4a612548 - f5ad172144ccd2dd62ece74ff0fb14641d936a80c1a0c93ebf97727184897cbc: !List - - 48be23172ae884459ae78334a0063f09fa0e317bea8b233ce782a38875e796b8 - - min: 0 - max: 39 - f9170804ddae0479f8d5af74ab3bd202e6ea4172d9a9b93707151adb7fc40ca1: !Enum - - name: a - tag: 97 - - name: b - tag: 98 - - name: c - tag: 99 - - name: d - tag: 100 - - name: e - tag: 101 - - name: f - tag: 102 - - name: g - tag: 103 - - name: h - tag: 104 - - name: i - tag: 105 - - name: j - tag: 106 - - name: k - tag: 107 - - name: l - tag: 108 - - name: m - tag: 109 - - name: n - tag: 110 - - name: o - tag: 111 - - name: p - tag: 112 - - name: q - tag: 113 - - name: r - tag: 114 - - name: s - tag: 115 - - name: t - tag: 116 - - name: u - tag: 117 - - name: v - tag: 118 - - name: w - tag: 119 - - name: x - tag: 120 - - name: y - tag: 121 - - name: z - tag: 122 - fba958721a3d335406b368c36f5a82790960cce239febcafe189ba9839d5da78: UnicodeChar -scripts: -- isae: - - ALU - - BPDIGEST - - RGB - code: - - 11 - - 0 - - 0 - - 0 - - 208 - - 160 - - 15 - - 1 - - 7 - - 11 - - 0 - - 1 - - 0 - - 11 - - 8 - - 0 - - 0 - - 11 - - 1 - - 2 - - 0 - - 200 - - 218 - - 7 - - 1 - - 57 - - 48 - - 0 - - 209 - - 160 - - 15 - - 1 - - 7 - data: - - 0 - - 1 - - 0 - - 0 - libs: [] -attachments: {} -signatures: {} diff --git a/tests/issuance.rs b/tests/issuance.rs index 16a7bdf..0f344ac 100644 --- a/tests/issuance.rs +++ b/tests/issuance.rs @@ -1,87 +1,217 @@ pub mod utils; +use ifaces::{EmbeddedMedia, MediaType, ProofOfReserves}; use rstest_reuse::{self, *}; -use utils::*; +use utils::{chain::initialize, helper::wallet::get_wallet, DescriptorType, *}; +#[allow(dead_code)] const MEDIA_FPATH: &str = "tests/fixtures/rgb_logo.jpeg"; #[template] #[rstest] -#[case(DescriptorType::Wpkh, CloseMethod::OpretFirst)] -#[case(DescriptorType::Wpkh, CloseMethod::TapretFirst)] -#[case(DescriptorType::Tr, CloseMethod::OpretFirst)] -#[case(DescriptorType::Tr, CloseMethod::TapretFirst)] -fn descriptor_and_close_method( - #[case] wallet_desc: DescriptorType, - #[case] close_method: CloseMethod, -) { +#[case(DescriptorType::Wpkh)] +#[case(DescriptorType::Tr)] +fn descriptor(#[case] wallet_desc: DescriptorType) {} + +#[apply(descriptor)] +fn issue_nia(wallet_desc: DescriptorType) { + println!("wallet_desc {wallet_desc:?}"); + + initialize(); + + let mut wallet = get_wallet(&wallet_desc); + + // Create NIA issuance parameters + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", 1_000_000); + + // Add initial allocations + let fake_outpoint_zero = + Outpoint::from_str("0000000000000000000000000000000000000000000000000000000000000000:0") + .unwrap(); + let fake_outpoint_one = + Outpoint::from_str("0000000000000000000000000000000000000000000000000000000000000001:0") + .unwrap(); + params + .add_allocation(fake_outpoint_zero, 500_000) + .add_allocation(fake_outpoint_one, 500_000); + + // Issue the contract + let contract_id = wallet.issue_nia_with_params(params); + + // Verify contract state + let state = wallet + .contract_state(contract_id) + .expect("Contract state does not exist"); + + // Verify immutable state + assert_eq!(state.immutable.name, "TestAsset"); + assert_eq!(state.immutable.ticker, "TEST"); + assert_eq!(state.immutable.precision, "centiMilli"); + + // Verify circulating supply + assert_eq!(state.immutable.circulating_supply, 1_000_000); + + // Verify ownership state + assert_eq!(state.owned.allocations.len(), 2); + assert!(state + .owned + .allocations + .iter() + .any(|(outpoint, amount)| outpoint.primary == fake_outpoint_zero && *amount == 500_000)); + assert!(state + .owned + .allocations + .iter() + .any(|(outpoint, amount)| outpoint.primary == fake_outpoint_one && *amount == 500_000)); } -#[apply(descriptor_and_close_method)] -fn issue_nia(wallet_desc: DescriptorType, close_method: CloseMethod) { - println!("wallet_desc {wallet_desc:?} close_method {close_method:?}"); +#[apply(descriptor)] +fn issue_fua(wallet_desc: DescriptorType) { + println!("wallet_desc {wallet_desc:?}"); initialize(); let mut wallet = get_wallet(&wallet_desc); - let issued_supply = 999; - let ticker = "TCKR"; - let name = "asset name"; - let precision = 2; - let details = Some("some details"); - let terms_text = "Ricardian contract"; - let terms_media_fpath = Some(MEDIA_FPATH); - let asset_info = AssetInfo::nia( - ticker, - name, - precision, - details, - terms_text, - terms_media_fpath, - vec![issued_supply], - ); - let (contract_id, iface_type_name) = wallet.issue_with_info(asset_info, close_method, vec![]); - - let contract = wallet.contract_iface_class::(contract_id); - let spec = contract.spec(); - assert_eq!(spec.ticker.to_string(), ticker.to_string()); - assert_eq!(spec.name.to_string(), name.to_string()); - assert_eq!(spec.precision.decimals(), precision); - let terms = contract.contract_terms(); - assert_eq!(terms.text.to_string(), terms_text.to_string()); - let terms_media = terms.media.unwrap(); - assert_eq!(terms_media.ty.to_string(), "image/jpeg"); - assert_eq!( - terms_media.digest.to_string(), - "02d2cc5d7883885bb7472e4fe96a07344b1d7cf794cb06943e1cdb5c57754d8a" - ); - assert_eq!(contract.total_issued_supply().value(), issued_supply); + // Create CFA issuance parameters + let mut params = FUAIssueParams::new("DemoCFA", "details", "centiMilli", 10_000); + + // Add initial allocation + let fake_outpoint = + Outpoint::from_str("b7116550736fbe5d3e234d0141c6bc8d1825f94da78514a3cede5674e9a5eae9:1") + .unwrap(); + params.add_allocation(fake_outpoint, 10_000); + + // Issue the contract + let contract_id = wallet.issue_fua_with_params(params); + + // Verify contract state + let state = wallet + .contract_state(contract_id) + .expect("Contract state does not exist"); + + // Verify immutable state + assert_eq!(state.immutable.name, "DemoCFA"); + assert_eq!(state.immutable.precision, "centiMilli"); + assert_eq!(state.immutable.circulating_supply, 10_000); + + // Verify ownership state + assert_eq!(state.owned.allocations.len(), 1); + assert!(state + .owned + .allocations + .iter() + .any(|(outpoint, amount)| outpoint.primary == fake_outpoint && *amount == 10_000)); +} + +#[apply(descriptor)] +fn issue_fua_multiple_utxos(wallet_desc: DescriptorType) { + println!("wallet_desc {wallet_desc:?}"); + + initialize(); + + let mut wallet = get_wallet(&wallet_desc); - let allocations = wallet.contract_fungible_allocations(contract_id, &iface_type_name, false); - assert_eq!(allocations.len(), 1); - let allocation = allocations[0]; - assert_eq!(allocation.seal.method(), close_method); - assert_eq!(allocation.state, Amount::from(issued_supply)); + // Create FUA issuance parameters with multiple allocations + let mut params = FUAIssueParams::new("Multi_UTXO_CFA", "details", "centiMilli", 999); + + // Get multiple UTXOs and add allocations + let amounts = [222, 444, 333]; + for amount in amounts.iter() { + let outpoint = wallet.get_utxo(None); + params.add_allocation(outpoint, *amount); + } + + // Issue the contract + let contract_id = wallet.issue_fua_with_params(params); + + // Verify contract state + let state = wallet + .contract_state(contract_id) + .expect("Contract state does not exist"); + + // Verify immutable state + assert_eq!(state.immutable.name, "Multi_UTXO_CFA"); + assert_eq!(state.immutable.precision, "centiMilli"); + assert_eq!(state.immutable.circulating_supply, 999); + + // Verify ownership state + assert_eq!(state.owned.allocations.len(), 3); + let total_allocated: u64 = state + .owned + .allocations + .iter() + .map(|(_, amount)| amount) + .sum(); + assert_eq!(total_allocated, 999); +} + +#[apply(descriptor)] +fn issue_nia_multiple_utxos(wallet_desc: DescriptorType) { + println!("wallet_desc {wallet_desc:?}"); + + initialize(); + + let mut wallet = get_wallet(&wallet_desc); + + // Create NIA issuance parameters with multiple allocations + let mut params = NIAIssueParams::new("Multi_UTXO_NIA", "MUTX", "centiMilli", 999); + + // Get multiple UTXOs and add allocations + let amounts = [333, 333, 333]; + for amount in amounts.iter() { + let outpoint = wallet.get_utxo(None); + params.add_allocation(outpoint, *amount); + } + + // Issue the contract + let contract_id = wallet.issue_nia_with_params(params); + + // Verify contract state + let state = wallet + .contract_state(contract_id) + .expect("Contract state does not exist"); + + // Verify immutable state + assert_eq!(state.immutable.name, "Multi_UTXO_NIA"); + assert_eq!(state.immutable.ticker, "MUTX"); + assert_eq!(state.immutable.precision, "centiMilli"); + assert_eq!(state.immutable.circulating_supply, 999); + + // Verify ownership state + assert_eq!(state.owned.allocations.len(), 3); + let total_allocated: u64 = state + .owned + .allocations + .iter() + .map(|(_, amount)| amount) + .sum(); + assert_eq!(total_allocated, 999); } -#[apply(descriptor_and_close_method)] -fn issue_uda(wallet_desc: DescriptorType, close_method: CloseMethod) { - println!("wallet_desc {wallet_desc:?} close_method {close_method:?}"); +#[apply(descriptor)] +#[ignore = "failed to issue contract: Inner(Genesis(Named(TypeName('DigitalCollection')), ScriptUnspecified))"] +fn issue_fac(wallet_desc: DescriptorType) { + println!("wallet_desc {wallet_desc:?}"); initialize(); let mut wallet = get_wallet(&wallet_desc); + // Create FAC asset parameters + let mut fac_params = FACIssueParams::new( + "DigitalCollection", + "A collection of digital assets", + 10_000, + ); + let ticker = "TCKR"; let name = "asset name"; - let details = Some("some details"); - let terms_text = "Ricardian contract"; - let terms_media_fpath = Some(MEDIA_FPATH); + let details = "some details"; let data = vec![1u8, 3u8, 9u8]; let preview_ty = "image/jpeg"; let token_data_preview = EmbeddedMedia { - ty: MediaType::with(preview_ty), + mime: MediaType::with(preview_ty), data: Confined::try_from(data.clone()).unwrap(), }; let proof = vec![2u8, 4u8, 6u8, 10u8]; @@ -89,180 +219,64 @@ fn issue_uda(wallet_desc: DescriptorType, close_method: CloseMethod) { utxo: Outpoint::from_str(FAKE_TXID).unwrap(), proof: Confined::try_from(proof.clone()).unwrap(), }; - let token_data_ticker = "TDTCKR"; - let token_data_name = "token data name"; - let token_data_details = "token data details"; let token_data_attachment = attachment_from_fpath(MEDIA_FPATH); let mut token_data_attachments = BTreeMap::new(); for (idx, attachment_fpath) in ["README.md", "Cargo.toml"].iter().enumerate() { token_data_attachments.insert(idx as u8, attachment_from_fpath(attachment_fpath)); } - let token_data = uda_token_data( - token_data_ticker, - token_data_name, - token_data_details, + + let nft_spec = nft_spec( + name, token_data_preview.clone(), token_data_attachment.clone(), - token_data_attachments.clone(), token_data_reserves.clone(), ); - let asset_info = AssetInfo::uda( - ticker, - name, - details, - terms_text, - terms_media_fpath, - token_data, - ); - let (contract_id, iface_type_name) = wallet.issue_with_info(asset_info, close_method, vec![]); - - let contract = wallet.contract_iface_class::(contract_id); - let spec = contract.spec(); - assert_eq!(spec.ticker.to_string(), ticker.to_string()); - assert_eq!(spec.name.to_string(), name.to_string()); - assert_eq!(spec.precision.decimals(), 0); - let terms = contract.contract_terms(); - assert_eq!(terms.text.to_string(), terms_text.to_string()); - let terms_media = terms.media.unwrap(); - assert_eq!(terms_media.ty.to_string(), "image/jpeg"); - assert_eq!( - terms_media.digest.to_string(), - "02d2cc5d7883885bb7472e4fe96a07344b1d7cf794cb06943e1cdb5c57754d8a" - ); - let token_data = contract.token_data(); - assert_eq!(token_data.index, TokenIndex::from(0)); - assert_eq!(token_data.ticker.unwrap().to_string(), token_data_ticker); - assert_eq!(token_data.name.unwrap().to_string(), token_data_name); - assert_eq!(token_data.details.unwrap().to_string(), token_data_details); - assert_eq!(token_data.preview.unwrap(), token_data_preview); - assert_eq!(token_data.media.unwrap(), token_data_attachment); - assert_eq!( - token_data.attachments.to_unconfined(), - token_data_attachments - ); - assert_eq!(token_data.reserves.unwrap(), token_data_reserves); - - let allocations = wallet.contract_data_allocations(contract_id, &iface_type_name); - assert_eq!(allocations.len(), 1); - let allocation = &allocations[0]; - assert_eq!(allocation.seal.method(), close_method); - assert_eq!(allocation.state.to_string(), "000000000100000000000000"); -} - -#[apply(descriptor_and_close_method)] -fn issue_cfa(wallet_desc: DescriptorType, close_method: CloseMethod) { - println!("wallet_desc {wallet_desc:?} close_method {close_method:?}"); - - initialize(); - - let mut wallet = get_wallet(&wallet_desc); - let issued_supply = 999; - let name = "asset name"; - let precision = 2; - let details = Some("some details"); - let terms_text = "Ricardian contract"; - let terms_media_fpath = Some(MEDIA_FPATH); - let asset_info = AssetInfo::cfa( - name, - precision, - details, - terms_text, - terms_media_fpath, - vec![issued_supply], + // Create allocation + let outpoint = wallet.get_utxo(None); + fac_params.with_allocation(outpoint, 10_000); + fac_params.with_nft_spec(nft_spec); + // Issue the contract + let contract_id = wallet.issue_fac_with_params(fac_params); + println!("FAC contract issued with ID: {}", contract_id); + + let state = wallet.contract_state_rgb21(contract_id).unwrap(); + let token = state.immutable.token.unwrap(); + assert_eq!(state.immutable.name.as_str(), "DigitalCollection"); + assert_eq!(state.immutable.total_fractions, 10_000); + assert_eq!(token.ticker.unwrap().to_string(), ticker); + assert_eq!(token.name.unwrap().to_string(), name); + assert_eq!(token.details.unwrap().to_string(), details); + assert_eq!( + token.preview.as_ref().unwrap().media_type.r#type.as_str(), + token_data_preview.mime.ty.as_str() ); - let (contract_id, iface_type_name) = wallet.issue_with_info(asset_info, close_method, vec![]); - let contract = wallet.contract_iface_class::(contract_id); - assert_eq!(contract.name().to_string(), name.to_string()); assert_eq!( - contract.details().map(|d| d.to_string()), - details.map(|d| d.to_string()) + token.preview.as_ref().unwrap().data.as_slice(), + token_data_preview.data.as_slice() ); - assert_eq!(contract.precision().decimals(), precision); - let terms = contract.contract_terms(); - assert_eq!(terms.text.to_string(), terms_text.to_string()); - let terms_media = terms.media.unwrap(); - assert_eq!(terms_media.ty.to_string(), "image/jpeg"); assert_eq!( - terms_media.digest.to_string(), - "02d2cc5d7883885bb7472e4fe96a07344b1d7cf794cb06943e1cdb5c57754d8a" + token.media.as_ref().unwrap().digest.as_slice(), + token_data_attachment.digest.as_slice() ); - assert_eq!(contract.total_issued_supply().value(), issued_supply); - - let allocations = wallet.contract_fungible_allocations(contract_id, &iface_type_name, false); - assert_eq!(allocations.len(), 1); - let allocation = allocations[0]; - assert_eq!(allocation.seal.method(), close_method); - assert_eq!(allocation.state, Amount::from(issued_supply)); -} - -#[apply(descriptor_and_close_method)] -fn issue_nia_multiple_utxos(wallet_desc: DescriptorType, close_method: CloseMethod) { - println!("wallet_desc {wallet_desc:?} close_method {close_method:?}"); - - initialize(); - - let mut wallet = get_wallet(&wallet_desc); - - let amounts = vec![222, 444, 333]; - let outpoints: Vec<_> = (0..amounts.len()) - .map(|_| Some(wallet.get_utxo(None))) - .collect(); - let asset_info = AssetInfo::default_nia(amounts.clone()); - let (contract_id, iface_type_name) = - wallet.issue_with_info(asset_info, close_method, outpoints.clone()); - - let contract = wallet.contract_iface_class::(contract_id); + // token_data_attachments + for (idx, attachment) in token.attachments.iter() { + assert_eq!( + attachment.digest.as_slice(), + token_data_attachments[idx].digest.as_slice() + ); + } assert_eq!( - contract.total_issued_supply().value(), - amounts.iter().sum::() + token.reserves.as_ref().unwrap().utxo.to_string(), + token_data_reserves.utxo.to_string() ); - - let allocations = wallet.contract_fungible_allocations(contract_id, &iface_type_name, false); - assert_eq!(allocations.len(), amounts.len()); - for (amt, outpoint) in amounts.iter().zip(outpoints.into_iter()) { - assert!(allocations.iter().any(|a| a.state == Amount::from(*amt) - && a.seal - == XChain::Bitcoin(ExplicitSeal { - method: close_method, - txid: outpoint.unwrap().txid, - vout: outpoint.unwrap().vout - }))) - } -} - -#[apply(descriptor_and_close_method)] -fn issue_cfa_multiple_utxos(wallet_desc: DescriptorType, close_method: CloseMethod) { - println!("wallet_desc {wallet_desc:?} close_method {close_method:?}"); - - initialize(); - - let mut wallet = get_wallet(&wallet_desc); - - let amounts = vec![222, 444, 333]; - let outpoints: Vec<_> = (0..amounts.len()) - .map(|_| Some(wallet.get_utxo(None))) - .collect(); - let asset_info = AssetInfo::default_cfa(amounts.clone()); - let (contract_id, iface_type_name) = - wallet.issue_with_info(asset_info, close_method, outpoints.clone()); - - let contract = wallet.contract_iface_class::(contract_id); assert_eq!( - contract.total_issued_supply().value(), - amounts.iter().sum::() + token.reserves.as_ref().unwrap().proof.as_slice(), + token_data_reserves.proof.as_slice() ); - let allocations = wallet.contract_fungible_allocations(contract_id, &iface_type_name, false); - assert_eq!(allocations.len(), amounts.len()); - for (amt, outpoint) in amounts.iter().zip(outpoints.into_iter()) { - assert!(allocations.iter().any(|a| a.state == Amount::from(*amt) - && a.seal - == XChain::Bitcoin(ExplicitSeal { - method: close_method, - txid: outpoint.unwrap().txid, - vout: outpoint.unwrap().vout - }))) - } + assert_eq!(state.owned.fractions.len(), 1); + assert_eq!(state.owned.fractions[0].0.to_string(), outpoint.to_string()); + assert_eq!(state.owned.fractions[0].1, 10_000); } diff --git a/tests/start_services.sh b/tests/start_services.sh deleted file mode 100755 index ff32e6c..0000000 --- a/tests/start_services.sh +++ /dev/null @@ -1,129 +0,0 @@ -#!/bin/bash -set -eu - -_die () { - echo "ERR: $*" >&2 - exit 1 -} - -_prepare_bitcoin_nodes() { - $BCLI_1 createwallet miner - $BCLI_2 createwallet miner - $BCLI_3 createwallet miner - $BCLI_1 -rpcwallet=miner -generate 103 - $BCLI_2 -rpcwallet=miner -generate 103 - # connect the 2 bitcoin services for the reorg - if [ "$PROFILE" == "esplora" ]; then - $BCLI_2 addnode "esplora_3:18444" "onetry" - $BCLI_3 addnode "esplora_2:18444" "onetry" - elif [ "$PROFILE" == "electrum" ]; then - $BCLI_2 addnode "bitcoind_3:18444" "onetry" - $BCLI_3 addnode "bitcoind_2:18444" "onetry" - fi -} - -_wait_for_bitcoind() { - # wait for bitcoind to be up - bitcoind_service_name="$1" - until $COMPOSE logs $bitcoind_service_name |grep -q 'Bound to'; do - sleep 1 - done -} - -_wait_for_electrs() { - # wait for electrs to have completed startup - electrs_service_name="$1" - until $COMPOSE logs $electrs_service_name |grep -q 'finished full compaction'; do - sleep 1 - done -} - -_wait_for_esplora() { - # wait for esplora to have completed startup - esplora_service_name="$1" - until $COMPOSE logs $esplora_service_name |grep -q 'run: nginx:'; do - sleep 1 - done -} - -_stop_esplora() { - # stop an esplora sub service - esplora_service_name="$1" - esplora_sub_service_name="${2:-electrs}" - if $COMPOSE ps |grep -q $esplora_service_name; then - for SRV in socat $esplora_sub_service_name; do - $COMPOSE exec $esplora_service_name bash -c "sv -w 60 force-stop /etc/service/$SRV" - done - fi -} - -_stop_services() { - if [ "$PROFILE" == "esplora" ]; then - _stop_esplora esplora_1 - _stop_esplora esplora_2 - _stop_esplora esplora_3 - fi - # bring all services down - $COMPOSE --profile '*' down -v --remove-orphans -} - -_start_services() { - _stop_services - mkdir -p $TEST_DATA_DIR - for port in "${EXPOSED_PORTS[@]}"; do - if [ -n "$(ss -HOlnt "sport = :$port")" ];then - _die "port $port is already bound, services can't be started" - fi - done - $COMPOSE up -d -} - -COMPOSE="docker compose" -if ! $COMPOSE >/dev/null; then - _die "could not call docker compose (hint: install docker compose plugin)" -fi -COMPOSE="$COMPOSE -f tests/docker-compose.yml" -PROFILE=${PROFILE:-"esplora"} -COMPOSE="$COMPOSE --profile $PROFILE" -TEST_DATA_DIR="./test-data" - -# see docker-compose.yml for the exposed ports -if [ "$PROFILE" == "esplora" ]; then - BCLI_1="$COMPOSE exec -T esplora_1 cli" - BCLI_2="$COMPOSE exec -T esplora_2 cli" - BCLI_3="$COMPOSE exec -T esplora_3 cli" - EXPOSED_PORTS=(8094 8095 8096 50004 50005 50006) -elif [ "$PROFILE" == "electrum" ]; then - BCLI_1="$COMPOSE exec -T -u blits bitcoind_1 bitcoin-cli -regtest" - BCLI_2="$COMPOSE exec -T -u blits bitcoind_2 bitcoin-cli -regtest" - BCLI_3="$COMPOSE exec -T -u blits bitcoind_3 bitcoin-cli -regtest" - EXPOSED_PORTS=(50001 50002 50003) -else - _die "invalid profile" -fi - -# restart services (down + up) checking for ports availability -_start_services - -# wait for services (pre-mining) -if [ "$PROFILE" == "esplora" ]; then - _wait_for_esplora esplora_1 - _wait_for_esplora esplora_2 - _wait_for_esplora esplora_3 - _stop_esplora esplora_1 tor - _stop_esplora esplora_2 tor - _stop_esplora esplora_3 tor -elif [ "$PROFILE" == "electrum" ]; then - _wait_for_bitcoind bitcoind_1 - _wait_for_bitcoind bitcoind_2 - _wait_for_bitcoind bitcoind_3 -fi - -_prepare_bitcoin_nodes - -# wait for services (post-mining) -if [ "$PROFILE" == "electrum" ]; then - _wait_for_electrs electrs_1 - _wait_for_electrs electrs_2 - _wait_for_electrs electrs_3 -fi diff --git a/tests/stress.rs b/tests/stress.rs index e266758..26ec6d5 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -1,53 +1,152 @@ -pub mod utils; +// RGB v0.12 Migration Notes: +// 1. Seal Type Unification (RFC: https://github.com/RGB-WG/RFC/issues/16) +// - Unified seal type replaces distinct opret and tapret seals +// - Seal type is automatically determined by wallet type (Taproot/WPKH) +// - CloseMethod parameter has been removed from contract genesis +// - Contract no longer commits to specific seal types +// +// 2. API Changes and Migration Strategy: +// - Removed APIs: +// * update_witnesses: Will be replaced with new rollback procedure +// * CloseMethod related parameters: No longer needed due to seal unification +// - Test Case Handling: +// * Existing tests dependent on removed APIs: Marked as #[ignore] with tracking issues +// * New tests: Focus on wallet type interactions rather than seal types +// * Complex test cases will be implemented after evaluating: +// - RGB protocol documentation and examples +// - Implementation approaches for Lightning Network, multi-sig and interactive transactions + +#![allow(unused_imports)] -use utils::*; +use rstest::rstest; +use serial_test::serial; +use std::io::Write; +use std::path::PathBuf; +use std::str::FromStr; +use std::time::Instant; +use std::{env::VarError, fs::File}; +use time::format_description::well_known::Iso8601; +use time::{format_description, OffsetDateTime}; +use utils::{ + chain::initialize, + helper::reporting::{MetricDefinition, MetricType, Report}, + helper::wallet::{get_wallet, TransferType}, + DescriptorType, DEFAULT_FEE_ABS, STRESS_DATA_DIR, TEST_DATA_DIR, +}; +use utils::{fund_wallet, NIAIssueParams}; + +pub mod utils; -type TT = TransferType; +// Aliases for shorter test case definitions type DT = DescriptorType; #[rstest] -// blinded -#[case(TT::Blinded, DT::Wpkh, DT::Wpkh)] -#[case(TT::Blinded, DT::Wpkh, DT::Tr)] -#[case(TT::Blinded, DT::Tr, DT::Tr)] -// witness -#[case(TT::Witness, DT::Wpkh, DT::Wpkh)] -#[case(TT::Witness, DT::Wpkh, DT::Tr)] -#[case(TT::Witness, DT::Tr, DT::Tr)] -#[ignore = "run a single case if desired"] +#[case(false, DT::Wpkh, DT::Wpkh)] +#[case(false, DT::Wpkh, DT::Tr)] +#[case(false, DT::Tr, DT::Wpkh)] +#[case(false, DT::Tr, DT::Tr)] +#[case(true, DT::Wpkh, DT::Wpkh)] +#[case(true, DT::Wpkh, DT::Tr)] +#[case(true, DT::Tr, DT::Wpkh)] +#[case(true, DT::Tr, DT::Tr)] +#[serial] fn back_and_forth( - #[case] transfer_type: TransferType, + #[case] wout: bool, #[case] wlt_1_desc: DescriptorType, #[case] wlt_2_desc: DescriptorType, ) { - println!("transfer_type {transfer_type:?} wlt_1_desc {wlt_1_desc:?} wlt_2_desc {wlt_2_desc:?}"); + // case_7: `{\"code\":-26,\"message\":\"min relay fee not met, 600 < 671\"}"` + // Define a fee constant to prevent errors when the number of transaction inputs is too high + const MIN_RELAY_FEE: u64 = 800; + println!("wout {wout:?} wlt_1_desc {wlt_1_desc:?} wlt_2_desc {wlt_2_desc:?}"); initialize(); let stress_tests_dir = PathBuf::from(TEST_DATA_DIR).join(STRESS_DATA_DIR); std::fs::create_dir_all(&stress_tests_dir).unwrap(); - let fname = OffsetDateTime::unix_timestamp(OffsetDateTime::now_utc()).to_string(); - let mut fpath = stress_tests_dir.join(fname); + let summary_name = format!("wout_{wout}_wlt_1_{wlt_1_desc}_wlt_2_{wlt_2_desc}"); + + let format = + format_description::parse("[year]_[month]_[day]_[hour]_[minute]_[second]").unwrap(); + let date = OffsetDateTime::now_utc().format(&format).unwrap(); + let filename = format!("{}_{}", summary_name, date); + let mut fpath = stress_tests_dir.join(&filename); fpath.set_extension("csv"); println!("report path: {}", fpath.to_string_lossy()); - let report = Report { report_path: fpath }; - report.write_header(&[ - "wlt_1_pay", - "wlt_2_validate", - "wlt_2_accept", - "wlt_2_pay", - "wlt_1_validate", - "wlt_1_accept", - "send_1_tot", - "send_2_tot", - ]); - - let mut wlt_1 = get_wallet(&wlt_1_desc); - let mut wlt_2 = get_wallet(&wlt_2_desc); + + // Create Report instance with metrics + let metrics = vec![ + MetricDefinition { + name: "wlt_1_pay".to_string(), + metric_type: MetricType::Duration, + description: "Time taken for wallet 1 to pay".to_string(), + }, + MetricDefinition { + name: "wlt_1_pay_consignment_size".to_string(), + metric_type: MetricType::Bytes, + description: "Size of the consignment file for wallet 1".to_string(), + }, + MetricDefinition { + name: "wlt_1_pay_txin_count".to_string(), + metric_type: MetricType::Integer, + description: "Number of inputs in the transaction for wallet 1".to_string(), + }, + MetricDefinition { + name: "wlt_1_pay_txout_count".to_string(), + metric_type: MetricType::Integer, + description: "Number of outputs in the transaction for wallet 1".to_string(), + }, + MetricDefinition { + name: "wlt_2_accept".to_string(), + metric_type: MetricType::Duration, + description: "Time taken for wallet 2 to accept".to_string(), + }, + MetricDefinition { + name: "wlt_2_pay".to_string(), + metric_type: MetricType::Duration, + description: "Time taken for wallet 2 to pay".to_string(), + }, + MetricDefinition { + name: "wlt_2_pay_consignment_size".to_string(), + metric_type: MetricType::Bytes, + description: "Size of the consignment file for wallet 2".to_string(), + }, + MetricDefinition { + name: "wlt_2_pay_txin_count".to_string(), + metric_type: MetricType::Integer, + description: "Number of inputs in the transaction for wallet 2".to_string(), + }, + MetricDefinition { + name: "wlt_2_pay_txout_count".to_string(), + metric_type: MetricType::Integer, + description: "Number of outputs in the transaction for wallet 2".to_string(), + }, + MetricDefinition { + name: "wlt_1_accept".to_string(), + metric_type: MetricType::Duration, + description: "Time taken for wallet 1 to accept".to_string(), + }, + ]; + + let mut report = Report::new(fpath, metrics, Some(10)).unwrap(); + + let mut wlt_1 = get_wallet(&wlt_1_desc).with_id("wlt_1"); + let mut wlt_2 = get_wallet(&wlt_2_desc).with_id("wlt_2"); let issued_supply = u64::MAX; - let (contract_id, iface_type_name) = wlt_1.issue_nia(issued_supply, wlt_1.close_method(), None); + // In RGB v0.12, the close_method parameter is no longer required + // Create and issue assets + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", issued_supply); + // fund wlt_1 and get utxo + let utxo = wlt_1.get_utxo(None); + // fund wlt_2 + let _ = wlt_2.get_utxo(None); + + params.add_allocation(utxo, issued_supply); + let contract_id = wlt_1.issue_nia_with_params(params); + wlt_1.send_contract("TestAsset", &mut wlt_2); + wlt_2.reload_runtime(); let loops = match std::env::var("LOOPS") { Ok(val) if u16::from_str(&val).is_ok() => u16::from_str(&val).unwrap(), @@ -57,40 +156,49 @@ fn back_and_forth( } }; - let sats_base = 3000; + let sats_base = 3601; let mut sats_send = sats_base * loops as u64; let now = Instant::now(); for i in 1..=loops { println!("loop {i}/{loops}"); - sats_send -= DEFAULT_FEE_ABS * 2; - let wlt_1_send_start = Instant::now(); + sats_send -= MIN_RELAY_FEE * 2; + // In RGB v0.12, the send method parameters have been changed wlt_1.send( &mut wlt_2, - transfer_type, + wout, contract_id, - &iface_type_name, issued_supply - i as u64, sats_send, - Some(&report), + Some(MIN_RELAY_FEE), + None, + Some(&mut report), ); - let wlt_1_send_duration = wlt_1_send_start.elapsed(); - sats_send -= DEFAULT_FEE_ABS * 2; - let wlt_2_send_start = Instant::now(); + + // Here we subtract MIN_RELAY_FEE * 2 + // Because one MIN_RELAY_FEE is used for change, and one is used for fee + sats_send -= MIN_RELAY_FEE * 2; + wlt_2.send( &mut wlt_1, - transfer_type, + wout, contract_id, - &iface_type_name, issued_supply - i as u64 - 1, sats_send, - Some(&report), + Some(MIN_RELAY_FEE), + None, + Some(&mut report), ); - let wlt_2_send_duration = wlt_2_send_start.elapsed(); - report.write_duration(wlt_1_send_duration); - report.write_duration(wlt_2_send_duration); - report.end_line(); + // End the row for this iteration + report.end_row().unwrap(); } let elapsed = now.elapsed(); - println!("elapsed: {:.2?}", elapsed); + println!("Total time: {:.2?}", elapsed); + println!("Average time per transfer: {:.2?}", elapsed / loops as u32); + + // Generate and save test summary + match report.save_summary(&filename) { + Ok(summary) => println!("{}", std::fs::read_to_string(summary).unwrap()), + Err(e) => println!("Failed to save test summary: {}", e), + } } diff --git a/tests/templates/issuance/FAC.yaml b/tests/templates/issuance/FAC.yaml new file mode 100644 index 0000000..2bd8ed1 --- /dev/null +++ b/tests/templates/issuance/FAC.yaml @@ -0,0 +1,48 @@ +consensus: bitcoin +testnet: true +issuer: + codexId: aq_P8~q_-6FL9taO-OwXLij6-gfC3d0u-oH0rARg-KiFs7dM + version: 0 + api: TFKAmg + +name: DemoFAC +method: issue +timestamp: "2025-03-17T10:32:00-02:00" + +global: + - name: ticker + verified: NFT + - name: name + verified: FractionableAssetCollection + - name: maxFractions + verified: 10000 + - name: token + verified: + tokenNo: 0 + fractions: 10000 + unverified: + ticker: TCKR + name: asset name + details: some details + embedded: + type: + type: image + subtype: jpeg + charset: null + data: + - 1 + - 3 + - 9 + external: + type: + type: image + subtype: jpeg + charset: null + digest: 02d2cc5d7883885bb7472e4fe96a07344b1d7cf794cb06943e1cdb5c57754d8a + reserves: +owned: + - name: balance + seal: b7116550736fbe5d3e234d0141c6bc8d1825f94da78514a3cede5674e9a5eae9:1 + data: + tokenNo: 0 + fractions: 10000 diff --git a/tests/templates/issuance/FUA.yaml b/tests/templates/issuance/FUA.yaml new file mode 100644 index 0000000..fb619c1 --- /dev/null +++ b/tests/templates/issuance/FUA.yaml @@ -0,0 +1,25 @@ +consensus: bitcoin +testnet: true +issuer: + codexId: qg8TdlRF-~RGz7bI-pceS960-evWjLKg-NcWTNWy-D9pIYBA + version: 0 + api: r~mUOw +name: DemoFUA +method: issue +timestamp: "2025-03-17T10:32:00-02:00" + +global: + - name: details + verified: { } + unverified: first + - name: name + verified: FUA + - name: precision + verified: centiMilli + - name: issued + verified: 10000 + +owned: + - name: balance + seal: b7116550736fbe5d3e234d0141c6bc8d1825f94da78514a3cede5674e9a5eae9:1 + data: 10000 diff --git a/tests/templates/issuance/NFA.yaml b/tests/templates/issuance/NFA.yaml new file mode 100644 index 0000000..65e5732 --- /dev/null +++ b/tests/templates/issuance/NFA.yaml @@ -0,0 +1,24 @@ +consensus: bitcoin +testnet: true +issuer: + codexId: y6L7YTlM-5_v4LWy-oQsj5hV-I2imvxD-zRu0JBo-yaguhrY + version: 0 + api: rLosfg +name: DemoToken +method: issue +timestamp: "2025-04-27T10:32:00-02:00" + +global: + - name: ticker + verified: NFA + - name: name + verified: NFA + - name: precision + verified: centiMilli + - name: issued + verified: 10000 + +owned: + - name: balance + seal: b7116550736fbe5d3e234d0141c6bc8d1825f94da78514a3cede5674e9a5eae9:1 + data: 10000 diff --git a/tests/templates/schemata/RGB20-Simplest-v0-rLosfg.issuer b/tests/templates/schemata/RGB20-Simplest-v0-rLosfg.issuer new file mode 100644 index 0000000..408e7ff Binary files /dev/null and b/tests/templates/schemata/RGB20-Simplest-v0-rLosfg.issuer differ diff --git a/tests/templates/schemata/RGB21-UniqueNFT-v0-TFKAmg.issuer b/tests/templates/schemata/RGB21-UniqueNFT-v0-TFKAmg.issuer new file mode 100644 index 0000000..73c2537 Binary files /dev/null and b/tests/templates/schemata/RGB21-UniqueNFT-v0-TFKAmg.issuer differ diff --git a/tests/templates/schemata/RGB25-UniquelyFungible-v0-r~mUOw.issuer b/tests/templates/schemata/RGB25-UniquelyFungible-v0-r~mUOw.issuer new file mode 100644 index 0000000..75014b3 Binary files /dev/null and b/tests/templates/schemata/RGB25-UniquelyFungible-v0-r~mUOw.issuer differ diff --git a/tests/transfer.rs b/tests/transfer.rs new file mode 100644 index 0000000..3b4e8c2 --- /dev/null +++ b/tests/transfer.rs @@ -0,0 +1,1932 @@ +// RGB v0.12 Migration Notes: +// 1. Seal Type Unification (RFC: https://github.com/RGB-WG/RFC/issues/16) +// - Unified seal type replaces distinct opret and tapret seals +// - Seal type is automatically determined by wallet type (Taproot/WPKH) +// - CloseMethod parameter has been removed from contract genesis +// - Contract no longer commits to specific seal types +// +// 2. API Changes and Migration Strategy: +// - Removed APIs: +// * update_witnesses: Will be replaced with new rollback procedure +// * CloseMethod related parameters: No longer needed due to seal unification +// - Test Case Handling: +// * Existing tests dependent on removed APIs: Marked as #[ignore] with tracking issues +// * New tests: Focus on wallet type interactions rather than seal types +// * Complex test cases will be implemented after evaluating: +// - RGB protocol documentation and examples +// - Implementation approaches for Lightning Network, multi-sig and interactive transactions +// +// 3. Implementation Notes: +// - Test cases focus on wallet type (Taproot/WPKH) interactions +// - Complex test scenarios are defined but implementation deferred +// - Ignored tests will be updated once new APIs are available + +pub mod utils; + +use rgb::WitnessStatus; +use serial_test::serial; +use std::str::FromStr; +use utils::chain::{get_tx_height, tx_status}; +use utils::helper::wallet::{ + broadcast_tx_and_mine, get_mainnet_wallet, get_wallet, get_wallet_custom, AssetSchema, +}; +use utils::{ + chain::{ + connect_reorg_nodes, disconnect_reorg_nodes, get_height, get_height_custom, initialize, + mine_custom, stop_mining, + }, + DescriptorType, INSTANCE_2, INSTANCE_3, *, +}; + +use crate::utils::helper::wallet::{HistoryType, ReorgType}; + +type TT = TransferType; +type DT = DescriptorType; +type AS = AssetSchema; + +#[test] +fn rbf_transfer() { + initialize(); + + // Create two wallet instances + let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); + let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); + + // Create and issue NIA asset + let mut params = NIAIssueParams::new("RBFTestAsset", "RBF", "centiMilli", 600); + let outpoint = wlt_1.get_utxo(None); + params.add_allocation(outpoint, 600); + let contract_id = wlt_1.issue_nia_with_params(params); + wlt_1.send_contract("RBFTestAsset", &mut wlt_2); + wlt_2.reload_runtime(); + + let invoice = wlt_2.invoice(contract_id, 400, false, Some(0), None); + + // Stop mining to test RBF + stop_mining(); + let initial_height = get_height(); + + // First transfer attempt - with a lower fee + let (consignment_1, _tx, payment) = + wlt_1.transfer(invoice.clone(), None, Some(500), true, None); + let first_txid = _tx.txid(); + dbg!(first_txid, tx_status(first_txid, wlt_1.instance)); + + // Receiver accepts the transfer + wlt_2.accept_transfer(&consignment_1, None).unwrap(); + + // Verify block height hasn't changed (transaction not confirmed) + let mid_height = get_height(); + assert_eq!(initial_height, mid_height); + + // Second transfer attempt - with a higher fee for RBF + let (consignment_2, tx) = wlt_1.transfer_rbf(contract_id, payment, 1000, None); + let second_txid = tx.txid(); + // Verify block height still hasn't changed + let final_height = get_height(); + assert_eq!(initial_height, final_height); + + // Broadcast and confirm transaction + wlt_1.mine_tx(&tx.txid(), true); + dbg!(first_txid, tx_status(first_txid, wlt_1.instance)); + dbg!(second_txid, tx_status(second_txid, wlt_1.instance)); + + // Receiver accepts final transfer + wlt_2.accept_transfer(&consignment_2, None).unwrap(); + + // Sync both wallets + wlt_1.sync(); + wlt_2.sync(); + + // Verify asset allocations in both wallets + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![200]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![400]); + + // Transfer assets back to sender + wlt_2.send( + &mut wlt_1, + false, + contract_id, + 400, + 2000, + None, + Some(0), + None, + ); +} + +#[test] +fn rbf_unbroadcasted_state_all() { + initialize(); + + // Create two wallet instances + let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); + let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); + + // Create and issue NIA asset + let mut params = NIAIssueParams::new("RBFTestAsset", "RBF", "centiMilli", 600); + let outpoint = wlt_1.get_utxo(None); + params.add_allocation(outpoint, 600); + let contract_id = wlt_1.issue_nia_with_params(params); + wlt_1.send_contract("RBFTestAsset", &mut wlt_2); + wlt_2.reload_runtime(); + + let invoice = wlt_2.invoice(contract_id, 400, false, Some(0), None); + + // Stop mining to test RBF + stop_mining(); + let initial_height = get_height(); + + // First transfer attempt - with a lower fee + let (consignment_1, first_tx, payment) = + wlt_1.transfer(invoice.clone(), None, Some(500), false, None); + let first_txid = first_tx.txid(); + dbg!(first_txid, tx_status(first_txid, wlt_1.instance)); + + // Receiver accepts the transfer + wlt_2.accept_transfer(&consignment_1, None).unwrap(); + + // Verify block height hasn't changed (transaction not confirmed) + let mid_height = get_height(); + assert_eq!(initial_height, mid_height); + + // Second transfer -- just make it + let unbroadcast_psbt = wlt_1.runtime.rbf(&payment, 1000_u64).unwrap(); + + // Verify block height still hasn't changed + let final_height = get_height(); + assert_eq!(initial_height, final_height); + + // Only broadcast and confirm first transaction + wlt_1.broadcast_tx(&first_tx); + wlt_1.mine_tx(&first_tx.txid(), true); + dbg!(first_txid, tx_status(first_txid, wlt_1.instance)); + + // Sync both wallets + wlt_1.sync(); + wlt_2.sync(); + + println!("broadcasted tx: {}", first_tx.txid()); + println!("unbroadcasted tx: {}", unbroadcast_psbt.txid()); + dbg!(wlt_1.runtime.state_own(contract_id).owned); + dbg!(wlt_2.runtime.state_own(contract_id).owned); + + dbg!("all", wlt_1.runtime.state_all(contract_id).owned); + let wlt_1_state_all = wlt_1.runtime.state_all(contract_id).owned; + let unbroadcast_txid = unbroadcast_psbt.txid(); + // get the status of the unbroadcast_txid + let wlt_1_state_all_unbroadcast = wlt_1_state_all + .iter() + .find_map(|(_, states)| { + states + .iter() + .find(|s| s.assignment.seal.primary.txid == unbroadcast_txid) + .map(|s| s.status) + }) + .unwrap(); + assert_eq!(wlt_1_state_all_unbroadcast, WitnessStatus::Archived); + dbg!("unbroadcast", unbroadcast_txid, wlt_1_state_all_unbroadcast); + + // Verify asset allocations in both wallets + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![200]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![400]); +} + +#[rstest] +// blinded: nia - nia +#[case(TT::Blinded, DT::Wpkh, DT::Wpkh, AS::RGB20, AS::RGB20)] +#[case(TT::Blinded, DT::Wpkh, DT::Tr, AS::RGB20, AS::RGB20)] +#[case(TT::Blinded, DT::Tr, DT::Wpkh, AS::RGB20, AS::RGB20)] +#[case(TT::Blinded, DT::Tr, DT::Tr, AS::RGB20, AS::RGB20)] +// blinded: nia - cfa +#[case(TT::Blinded, DT::Wpkh, DT::Wpkh, AS::RGB20, AS::RGB25)] +#[case(TT::Blinded, DT::Wpkh, DT::Tr, AS::RGB20, AS::RGB25)] +#[case(TT::Blinded, DT::Tr, DT::Wpkh, AS::RGB20, AS::RGB25)] +#[case(TT::Blinded, DT::Tr, DT::Tr, AS::RGB20, AS::RGB25)] +// blinded: cfa - cfa +#[case(TT::Blinded, DT::Wpkh, DT::Wpkh, AS::RGB25, AS::RGB25)] +#[case(TT::Blinded, DT::Wpkh, DT::Tr, AS::RGB25, AS::RGB25)] +#[case(TT::Blinded, DT::Tr, DT::Wpkh, AS::RGB25, AS::RGB25)] +#[case(TT::Blinded, DT::Tr, DT::Tr, AS::RGB25, AS::RGB25)] +// TODO: UDA related asset feature, RGB core library is being improved, +// And the test case for UDA assets will be added later + +fn transfer_loop( + #[case] transfer_type: TransferType, + #[case] wlt_1_desc: DescriptorType, + #[case] wlt_2_desc: DescriptorType, + #[case] asset_schema_1: AssetSchema, + #[case] asset_schema_2: AssetSchema, +) { + println!( + "transfer_type {transfer_type:?} wlt_1_desc {wlt_1_desc:?} wlt_2_desc {wlt_2_desc:?} \ + asset_schema_1 {asset_schema_1:?} asset_schema_2 {asset_schema_2:?}" + ); + + initialize(); + + let mut wlt_1 = get_wallet(&wlt_1_desc); + let mut wlt_2 = get_wallet(&wlt_2_desc); + + let issued_supply_1 = 999; + let issued_supply_2 = 666; + + let mut sats = 9000; + + // wlt_1 issues 2 assets on the same UTXO + let utxo = wlt_1.get_utxo(None); + + // Issue first asset + let contract_id_1 = match asset_schema_1 { + AssetSchema::RGB20 => { + let mut params = + NIAIssueParams::new("TestAsset1", "TEST1", "centiMilli", issued_supply_1); + params.add_allocation(utxo, issued_supply_1); + wlt_1.issue_nia_with_params(params) + } + AssetSchema::RGB25 => { + let mut params = + FUAIssueParams::new("TestAsset1", "details", "centiMilli", issued_supply_1); + params.add_allocation(utxo, issued_supply_1); + wlt_1.issue_fua_with_params(params) + } + AssetSchema::RGB21 => { + // TODO: UDA is not supported yet + panic!("UDA is not supported yet"); + } + }; + + // Issue second asset + let contract_id_2 = match asset_schema_2 { + AssetSchema::RGB20 => { + let mut params = + NIAIssueParams::new("TestAsset2", "TEST2", "centiMilli", issued_supply_2); + params.add_allocation(utxo, issued_supply_2); + wlt_1.issue_nia_with_params(params) + } + AssetSchema::RGB25 => { + let mut params = + FUAIssueParams::new("TestAsset2", "details", "centiMilli", issued_supply_2); + params.add_allocation(utxo, issued_supply_2); + wlt_1.issue_fua_with_params(params) + } + AssetSchema::RGB21 => { + // TODO: UDA is not supported yet + panic!("UDA is not supported yet"); + } + }; + + // Share contract info with wallet 2 + wlt_1.send_contract("TestAsset1", &mut wlt_2); + wlt_1.send_contract("TestAsset2", &mut wlt_2); + wlt_2.reload_runtime(); + + // Verify initial allocations + wlt_1.check_allocations(contract_id_1, asset_schema_1, vec![issued_supply_1]); + wlt_1.check_allocations(contract_id_2, asset_schema_2, vec![issued_supply_2]); + + // wlt_1 spends asset 1 + let amount_1 = if asset_schema_1 != AssetSchema::RGB21 { + 99 + } else { + 1 + }; + let wout = match transfer_type { + TransferType::Blinded => false, + TransferType::Witness => true, + }; + wlt_1.send( + &mut wlt_2, + wout, + contract_id_1, + amount_1, + sats, + None, + Some(0), + None, + ); + + // Verify allocations after first transfer + wlt_1.check_allocations( + contract_id_1, + asset_schema_1, + vec![issued_supply_1 - amount_1], + ); + wlt_1.check_allocations(contract_id_2, asset_schema_2, vec![issued_supply_2]); + wlt_2.check_allocations(contract_id_1, asset_schema_1, vec![amount_1]); + + // wlt_1 spends asset 1 change (only if possible) + if asset_schema_1 != AssetSchema::RGB21 { + let amount_2 = 33; + wlt_1.send( + &mut wlt_2, + wout, + contract_id_1, + amount_2, + sats, + None, + Some(0), + None, + ); + wlt_1.check_allocations( + contract_id_1, + asset_schema_1, + vec![issued_supply_1 - amount_1 - amount_2], + ); + wlt_1.check_allocations(contract_id_2, asset_schema_2, vec![issued_supply_2]); + wlt_2.check_allocations(contract_id_1, asset_schema_1, vec![amount_1, amount_2]); + } + + // wlt_1 spends asset 2 + let amount_3 = if asset_schema_2 != AssetSchema::RGB21 { + 22 + } else { + 1 + }; + wlt_1.send( + &mut wlt_2, + wout, + contract_id_2, + amount_3, + sats, + None, + None, + None, + ); + + // Verify final allocations + if asset_schema_1 != AssetSchema::RGB21 { + let amount_2 = 33; + wlt_1.check_allocations( + contract_id_1, + asset_schema_1, + vec![issued_supply_1 - amount_1 - amount_2], + ); + } else { + wlt_1.check_allocations( + contract_id_1, + asset_schema_1, + vec![issued_supply_1 - amount_1], + ); + } + wlt_1.check_allocations( + contract_id_2, + asset_schema_2, + vec![issued_supply_2 - amount_3], + ); + wlt_2.check_allocations(contract_id_2, asset_schema_2, vec![amount_3]); + + // wlt_2 spends received allocation(s) of asset 1 + let amount_4 = if asset_schema_1 != AssetSchema::RGB21 { + 111 + } else { + 1 + }; + let amount_2 = if asset_schema_1 != AssetSchema::RGB21 { + 33 + } else { + 0 + }; + sats -= 1000; + wlt_2.send( + &mut wlt_1, + wout, + contract_id_1, + amount_4, + sats, + None, + None, + None, + ); + wlt_1.check_allocations( + contract_id_1, + asset_schema_1, + vec![issued_supply_1 - amount_1 - amount_2, amount_4], + ); + wlt_1.check_allocations( + contract_id_2, + asset_schema_2, + vec![issued_supply_2 - amount_3], + ); + wlt_2.check_allocations( + contract_id_1, + asset_schema_1, + vec![amount_1 + amount_2 - amount_4], + ); + wlt_2.check_allocations(contract_id_2, asset_schema_2, vec![amount_3]); + + // wlt_2 spends asset 2 + let amount_5 = if asset_schema_2 != AssetSchema::RGB21 { + 11 + } else { + 1 + }; + sats -= 1000; + wlt_2.send( + &mut wlt_1, + wout, + contract_id_2, + amount_5, + sats, + None, + None, + None, + ); + wlt_1.check_allocations( + contract_id_1, + asset_schema_1, + vec![issued_supply_1 - amount_1 - amount_2, amount_4], + ); + wlt_1.check_allocations( + contract_id_2, + asset_schema_2, + vec![issued_supply_2 - amount_3, amount_5], + ); + + wlt_2.check_allocations( + contract_id_1, + asset_schema_1, + vec![amount_1 + amount_2 - amount_4], + ); + wlt_2.check_allocations(contract_id_2, asset_schema_2, vec![amount_3 - amount_5]); + + // wlt_1 spends asset 1, received back + let amount_6 = if asset_schema_1 != AssetSchema::RGB21 { + issued_supply_1 - amount_1 - amount_2 + amount_4 + } else { + 1 + }; + sats -= 1000; + wlt_1.send( + &mut wlt_2, + wout, + contract_id_1, + amount_6, + sats, + None, + None, + None, + ); + wlt_1.check_allocations(contract_id_1, asset_schema_1, vec![]); + + wlt_1.check_allocation_sum(contract_id_2, issued_supply_2 - amount_3 + amount_5); + + wlt_2.check_allocations( + contract_id_1, + asset_schema_1, + vec![amount_1 + amount_2 - amount_4, amount_6], + ); + wlt_2.check_allocations(contract_id_2, asset_schema_2, vec![amount_3 - amount_5]); + + // wlt_1 spends asset 2, received back + let amount_7 = if asset_schema_2 != AssetSchema::RGB21 { + issued_supply_2 - amount_3 + amount_5 + } else { + 1 + }; + sats -= 1000; + wlt_1.send( + &mut wlt_2, + wout, + contract_id_2, + amount_7, + sats, + None, + None, + None, + ); + wlt_1.check_allocations(contract_id_1, asset_schema_1, vec![]); + wlt_1.check_allocations(contract_id_2, asset_schema_2, vec![]); + wlt_2.check_allocations( + contract_id_1, + asset_schema_1, + vec![amount_1 + amount_2 - amount_4, amount_6], + ); + wlt_2.check_allocations( + contract_id_2, + asset_schema_2, + vec![amount_3 - amount_5, amount_7], + ); +} + +#[rstest] +#[case(TT::Blinded)] +#[case(TT::Witness)] +fn same_transfer_twice_update_witnesses(#[case] transfer_type: TransferType) { + println!("transfer_type {transfer_type:?}"); + + initialize(); + + let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); + let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); + + let issue_supply = 2000; + // Create and issue NIA asset + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", issue_supply); + let outpoint = wlt_1.get_utxo(None); + params.add_allocation(outpoint, issue_supply); + let contract_id = wlt_1.issue_nia_with_params(params); + wlt_1.send_contract("TestAsset", &mut wlt_2); + wlt_2.reload_runtime(); + + let amount = 100; + let wout = match transfer_type { + TransferType::Blinded => false, + TransferType::Witness => true, + }; + + let invoice = wlt_2.invoice(contract_id, amount, wout, Some(0), None); + let _ = wlt_1.transfer(invoice.clone(), None, Some(500), false, None); + + wlt_1.sync(); + + let (consignment, tx, _) = wlt_1.transfer(invoice, None, Some(1000), true, None); + wlt_1.mine_tx(&tx.txid(), false); + wlt_2.accept_transfer(&consignment, None).unwrap(); + wlt_1.sync(); + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![issue_supply - amount]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![amount]); + + wlt_2.send( + &mut wlt_1, + wout, + contract_id, + amount, + 1000, + None, + None, + None, + ); +} + +// Complex test cases - Implementation deferred to final phase +// These test cases will be implemented last, after evaluating: +// 1. Available documentation and examples from RGB protocol +// 2. If no official examples exist, Bitlight will explore implementation approaches for: +// - Lightning Network test-cases integration +// - Multi-signature operations +// - Interactive transaction construction +// Reference: https://github.com/RGB-WG/rgb/blob/v0.12/doc/Payments.md + +#[test] +#[ignore = "Pending Lightning Network integration documentation"] +fn ln_transfers() { + // TODO: Implement Lightning Network transfer tests +} + +#[test] +#[ignore = "Pending multi-signature workflow documentation"] +fn collaborative_transfer() { + // TODO: Implement multi-signature transfer tests +} + +#[rstest] +#[should_panic(expected = "Fulfill(StateInsufficient)")] +#[case(TT::Blinded)] +#[should_panic(expected = "Fulfill(StateInsufficient)")] +#[case(TT::Witness)] +fn same_transfer_twice_no_update_witnesses(#[case] transfer_type: TransferType) { + println!("transfer_type {transfer_type:?}"); + + initialize(); + + let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); + let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); + let mut wlt_3 = get_wallet(&DescriptorType::Wpkh); + + let issue_supply = 2000; + // Create and issue NIA asset + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", issue_supply); + let outpoint = wlt_1.get_utxo(None); + params.add_allocation(outpoint, issue_supply); + let contract_id = wlt_1.issue_nia_with_params(params); + wlt_1.send_contract("TestAsset", &mut wlt_2); + wlt_2.reload_runtime(); + wlt_1.send_contract("TestAsset", &mut wlt_3); + wlt_3.reload_runtime(); + + let amount = 100; + let wout = match transfer_type { + TransferType::Blinded => false, + TransferType::Witness => true, + }; + let wlt1_utxo = wlt_1.get_utxo(None); + let wlt2_utxo = wlt_2.get_utxo(None); + let wlt3_utxo = wlt_3.get_utxo(None); + wlt_1.set_force_stop_sync(true); + wlt_2.set_force_stop_sync(true); + wlt_3.set_force_stop_sync(true); + + let invoice = wlt_2.invoice(contract_id, amount, wout, Some(0), Some(wlt2_utxo)); + let (_, _tx, payment) = wlt_1.transfer(invoice.clone(), None, Some(500), false, None); + + let (consignment, _) = wlt_1.transfer_rbf(contract_id, payment, 1000, None); + + wlt_2.accept_transfer(&consignment, None).unwrap(); + + if transfer_type == TransferType::Blinded { + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![amount]); + } else { + // Since the receiver state is not updated, it treats the witness transaction as not mined and thus has no state + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + } + + let invoice = wlt_1.invoice(contract_id, amount, wout, Some(0), Some(wlt1_utxo)); + let (consignment, _tx, _payment) = + wlt_2.transfer(invoice.clone(), None, Some(500), false, None); + wlt_1.accept_transfer(&consignment, None).unwrap(); + + // The receiver will fail to accept the consignment + let invoice = wlt_3.invoice(contract_id, issue_supply, wout, Some(0), Some(wlt3_utxo)); + let (consignment, _tx, _payment) = + wlt_1.transfer(invoice.clone(), None, Some(500), false, None); + wlt_3.accept_transfer(&consignment, None).unwrap(); +} + +#[test] +fn accept_0conf() { + initialize(); + + let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); + let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); + + let issue_supply = 600; + // Create and issue NIA asset + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", issue_supply); + let outpoint = wlt_1.get_utxo(None); + params.add_allocation(outpoint, issue_supply); + let contract_id = wlt_1.issue_nia_with_params(params); + wlt_1.send_contract("TestAsset", &mut wlt_2); + wlt_2.reload_runtime(); + + let amt = 200; + let invoice = wlt_2.invoice(contract_id, amt, true, Some(0), None); + let (consignment, tx, _) = wlt_1.transfer(invoice.clone(), None, None, true, None); + let txid = tx.txid(); + + wlt_2.accept_transfer(&consignment, None).unwrap(); + + // wlt_2 sees the allocation even if TX has not been mined + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![amt]); + + wlt_1.sync(); + + let wlt_1_change_amt = issue_supply - amt; + + // after mining, wlt_1 doesn't need to get tentative allocations to see the change + wlt_1.mine_tx(&txid, false); + wlt_1.sync(); + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt_1_change_amt]); +} + +#[test] +#[serial] +fn tapret_wlt_receiving_opret() { + initialize(); + + let mut wlt_1 = get_wallet(&DescriptorType::Tr); + let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); + + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", 600); + let outpoint = wlt_1.get_utxo(None); + params.add_allocation(outpoint, 600); + let contract_id = wlt_1.issue_nia_with_params(params); + wlt_1.send_contract("TestAsset", &mut wlt_2); + wlt_2.reload_runtime(); + + // First transfer: wlt_1 -> wlt_2, transfer 400 + wlt_1.send(&mut wlt_2, false, contract_id, 400, 5000, None, None, None); + + // Second transfer: wlt_2 -> wlt_1, transfer 100 + let invoice = wlt_1.invoice(contract_id, 100, true, Some(0), None); + wlt_2.send_to_invoice(&mut wlt_1, invoice, None, None, None); + + // Third transfer: wlt_1 -> wlt_2, transfer 290 + wlt_1.send(&mut wlt_2, true, contract_id, 290, 1000, None, None, None); + + // Fourth transfer: wlt_2 -> wlt_1, transfer 560 + wlt_2.send(&mut wlt_1, false, contract_id, 560, 1000, None, None, None); + + // Fifth transfer: wlt_1 -> wlt_2, transfer 570 + wlt_1.send(&mut wlt_2, false, contract_id, 570, 1000, None, None, None); + + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![30, 570]); +} + +#[test] +#[serial] +fn check_fungible_history() { + initialize(); + + let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); + let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); + + let issue_supply = 600; + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", issue_supply); + let outpoint = wlt_1.get_utxo(None); + params.add_allocation(outpoint, issue_supply); + let contract_id = wlt_1.issue_nia_with_params(params); + wlt_1.send_contract("TestAsset", &mut wlt_2); + wlt_2.reload_runtime(); + + dbg!(wlt_1.runtime().state_own(contract_id).owned); + + // transfer + let amt = 200; + let (_, tx, _) = wlt_1.send(&mut wlt_2, true, contract_id, amt, 1000, None, None, None); + let _txid = tx.txid(); + + // debug contract state + dbg!(wlt_1.runtime().state_own(contract_id).owned); + dbg!(wlt_2.runtime().state_own(contract_id).owned); + + // check allocations + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![issue_supply - amt]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![amt]); +} + +#[test] +fn send_to_oneself() { + initialize(); + + let mut wlt = get_wallet(&DescriptorType::Wpkh); + + let issue_supply = 600; + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", issue_supply); + let outpoint = wlt.get_utxo(None); + params.add_allocation(outpoint, issue_supply); + let contract_id = wlt.issue_nia_with_params(params); + + // Transfer 200 to yourself + let amt = 200; + let invoice = wlt.invoice(contract_id, amt, true, Some(0), None); + let (consignment, tx, _) = wlt.transfer(invoice.clone(), None, None, true, None); + wlt.mine_tx(&tx.txid(), false); + wlt.accept_transfer(&consignment, None).unwrap(); + wlt.sync(); + + // debug contract state + dbg!(wlt.runtime().state_own(contract_id).owned); + + // check allocations + wlt.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![amt, issue_supply - amt], + ); +} + +#[rstest] +#[case(DT::Tr, DT::Tr)] +#[case(DT::Tr, DT::Wpkh)] +#[case(DT::Wpkh, DT::Tr)] +#[case(DT::Wpkh, DT::Wpkh)] +fn blank_tapret_opret( + #[case] descriptor_type_0: DescriptorType, + #[case] descriptor_type_1: DescriptorType, +) { + initialize(); + + let mut wlt_1 = get_wallet(&descriptor_type_0); + let mut wlt_2 = get_wallet(&descriptor_type_1); + + // Create and issue first NIA asset + let mut params_0 = NIAIssueParams::new("TestAsset1", "TEST1", "centiMilli", 200); + let outpoint = wlt_1.get_utxo(None); + params_0.add_allocation(outpoint, 200); + let contract_id_0 = wlt_1.issue_nia_with_params(params_0); + wlt_1.send_contract("TestAsset1", &mut wlt_2); + wlt_2.reload_runtime(); + + // Create and issue second NIA asset (to be moved in blank) + let mut params_1 = NIAIssueParams::new("TestAsset2", "TEST2", "centiMilli", 100); + params_1.add_allocation(outpoint, 100); + let contract_id_1 = wlt_1.issue_nia_with_params(params_1); + wlt_1.send_contract("TestAsset2", &mut wlt_2); + wlt_2.reload_runtime(); + + // First transfer: wlt_1 -> wlt_2, transfer 200 of first asset + wlt_1.send( + &mut wlt_2, + false, + contract_id_0, + 200, + 1000, + None, + None, + None, + ); + + // Second transfer: wlt_1 -> wlt_2, transfer 100 of second asset + // This tests the blank transfer functionality with different descriptor types + wlt_1.send( + &mut wlt_2, + false, + contract_id_1, + 100, + 1000, + None, + None, + None, + ); + + // Verify final allocations + wlt_1.check_allocations(contract_id_0, AssetSchema::RGB20, vec![]); + wlt_1.check_allocations(contract_id_1, AssetSchema::RGB20, vec![]); + wlt_2.check_allocations(contract_id_0, AssetSchema::RGB20, vec![200]); + wlt_2.check_allocations(contract_id_1, AssetSchema::RGB20, vec![100]); +} + +#[rstest] +#[case(HistoryType::Linear, ReorgType::ChangeOrder)] +#[case(HistoryType::Linear, ReorgType::Revert)] +#[case(HistoryType::Branching, ReorgType::ChangeOrder)] +#[case(HistoryType::Branching, ReorgType::Revert)] +#[case(HistoryType::Merging, ReorgType::ChangeOrder)] +#[case(HistoryType::Merging, ReorgType::Revert)] +#[serial] +fn reorg_history(#[case] history_type: HistoryType, #[case] reorg_type: ReorgType) { + println!("history_type {history_type:?} reorg_type {reorg_type:?}"); + + initialize(); + connect_reorg_nodes(); + + let mut wlt_1 = get_wallet_custom(&DescriptorType::Wpkh, INSTANCE_2); + let mut wlt_2 = get_wallet_custom(&DescriptorType::Wpkh, INSTANCE_2); + let mut wlt_3 = get_wallet_custom(&DescriptorType::Wpkh, INSTANCE_2); + + let issued_supply = 600; + + // Initialize contract based on history type + let contract_id = match history_type { + HistoryType::Linear | HistoryType::Branching => { + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", issued_supply); + let outpoint = wlt_1.get_utxo(None); + params.add_allocation(outpoint, issued_supply); + wlt_1.issue_nia_with_params(params) + } + HistoryType::Merging => { + // For merging, we create a contract with multiple allocations + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", 600); + params.add_allocation(wlt_1.get_utxo(None), 400); + // Adding a second allocation to the same outpoint + params.add_allocation(wlt_1.get_utxo(None), 200); + wlt_1.issue_nia_with_params(params) + } + }; + + wlt_1.send_contract("TestAsset", &mut wlt_2); + wlt_2.reload_runtime(); + wlt_1.send_contract("TestAsset", &mut wlt_3); + wlt_3.reload_runtime(); + + // Generate UTXOs before asset transfer to avoid mining blocks during transfer, affecting the test + let utxo_wlt_1_1 = wlt_1.get_utxo(None); + let utxo_wlt_1_2 = wlt_1.get_utxo(None); + let utxo_wlt_2_1 = wlt_2.get_utxo(None); + let utxo_wlt_2_2 = wlt_2.get_utxo(None); + dbg!(utxo_wlt_1_1, utxo_wlt_1_2, utxo_wlt_2_1, utxo_wlt_2_2); + mine_custom(false, INSTANCE_2, 6); + + dbg!(get_height_custom(INSTANCE_2)); + dbg!(get_height_custom(INSTANCE_3)); + + disconnect_reorg_nodes(); + + // Create transactions based on history type + let txs = match history_type { + HistoryType::Linear => { + // Set the coin selection strategy to true small size + // This setting is very important, it avoids selecting the output of the revert transaction as input + wlt_1.set_coinselect_strategy(CustomCoinselectStrategy::TrueSmallSize); + let amt_0 = 590; + // Create blinded invoice with specific UTXO + let invoice = wlt_2.invoice(contract_id, amt_0, false, Some(0), Some(utxo_wlt_2_1)); + let (_, tx_0, _) = wlt_1.send_to_invoice(&mut wlt_2, invoice, Some(1000), None, None); + let wlt_1_state = wlt_1.runtime().state_own(contract_id).owned; + let wlt_2_state = wlt_2.runtime().state_own(contract_id).owned; + dbg!(tx_0.txid(), wlt_1_state, wlt_2_state); + + let amt_1 = 100; + let invoice = wlt_1.invoice(contract_id, amt_1, false, Some(0), Some(utxo_wlt_1_1)); + let (_, tx_1, _) = wlt_2.send_to_invoice(&mut wlt_1, invoice, Some(1000), None, None); + let wlt_1_state = wlt_1.runtime().state_own(contract_id).owned; + let wlt_2_state = wlt_2.runtime().state_own(contract_id).owned; + dbg!(tx_1.txid(), wlt_1_state, wlt_2_state); + + let amt_2 = 80; + let invoice = wlt_2.invoice(contract_id, amt_2, false, Some(0), Some(utxo_wlt_2_2)); + let (_, tx_2, _) = wlt_1.send_to_invoice(&mut wlt_2, invoice, Some(1000), None, None); + let wlt_1_state = wlt_1.runtime().state_own(contract_id).owned; + let wlt_2_state = wlt_2.runtime().state_own(contract_id).owned; + dbg!(tx_2.txid(), wlt_1_state, wlt_2_state); + + vec![tx_0, tx_1, tx_2] + } + HistoryType::Branching => { + let amt_0 = 600; + let invoice = wlt_2.invoice(contract_id, amt_0, false, Some(0), Some(utxo_wlt_2_1)); + let (_, tx_0, _) = wlt_1.send_to_invoice(&mut wlt_2, invoice, Some(1000), None, None); + + let amt_1 = 200; + let invoice = wlt_1.invoice(contract_id, amt_1, false, Some(0), Some(utxo_wlt_1_1)); + let (_, tx_1, _) = wlt_2.send_to_invoice(&mut wlt_1, invoice, Some(1000), None, None); + + let amt_2 = amt_0 - amt_1 - 1; + let invoice = wlt_1.invoice(contract_id, amt_2, false, Some(0), Some(utxo_wlt_1_2)); + let (_, tx_2, _) = wlt_2.send_to_invoice(&mut wlt_1, invoice, Some(1000), None, None); + + vec![tx_0, tx_1, tx_2] + } + HistoryType::Merging => { + let amt_0 = 400; + let invoice = wlt_2.invoice(contract_id, amt_0, false, Some(0), Some(utxo_wlt_2_1)); + let (_, tx_0, _) = wlt_1.send_to_invoice(&mut wlt_2, invoice, None, None, None); + + let amt_1 = 200; + let invoice = wlt_2.invoice(contract_id, amt_1, false, Some(0), Some(utxo_wlt_2_2)); + let (_, tx_1, _) = wlt_1.send_to_invoice(&mut wlt_2, invoice, None, None, None); + + let amt_2 = amt_0 + amt_1 - 1; + let invoice = wlt_1.invoice(contract_id, amt_2, false, Some(0), Some(utxo_wlt_1_1)); + let (_, tx_2, _) = wlt_2.send_to_invoice(&mut wlt_1, invoice, None, None, None); + + vec![tx_0, tx_1, tx_2] + } + }; + + dbg!( + "before switch", + wlt_1.runtime().state_own(contract_id).owned + ); + dbg!( + "before switch", + wlt_2.runtime().state_own(contract_id).owned + ); + + let tx_0_instance_2_height = get_tx_height(txs[0].txid(), INSTANCE_2); + let tx_1_instance_2_height = get_tx_height(txs[1].txid(), INSTANCE_2); + let tx_2_instance_2_height = get_tx_height(txs[2].txid(), INSTANCE_2); + + // Test different reorg scenarios + match (history_type, reorg_type) { + (HistoryType::Linear, ReorgType::ChangeOrder) => { + broadcast_tx_and_mine(&txs[2], INSTANCE_3); + broadcast_tx_and_mine(&txs[1], INSTANCE_3); + broadcast_tx_and_mine(&txs[0], INSTANCE_3); + wlt_1.switch_to_instance(INSTANCE_3); + wlt_2.switch_to_instance(INSTANCE_3); + let wlt_1_alloc_1 = 10; + let wlt_1_alloc_2 = 20; + let wlt_2_alloc_1 = 490; + let wlt_2_alloc_2 = 80; + wlt_1.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![wlt_1_alloc_1, wlt_1_alloc_2], + ); + wlt_2.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![wlt_2_alloc_1, wlt_2_alloc_2], + ); + } + (HistoryType::Linear | HistoryType::Branching, ReorgType::Revert) => { + broadcast_tx_and_mine(&txs[1], INSTANCE_3); + broadcast_tx_and_mine(&txs[2], INSTANCE_3); + wlt_1.switch_to_instance(INSTANCE_3); + wlt_2.switch_to_instance(INSTANCE_3); + let wlt_1_alloc_1 = 600; + dbg!(tx_status(txs[0].txid(), INSTANCE_3)); + dbg!( + "after revert tx_0", + wlt_1.runtime().state_own(contract_id).owned + ); + dbg!( + "after revert tx_0", + wlt_2.runtime().state_own(contract_id).owned + ); + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt_1_alloc_1]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + } + (HistoryType::Branching, ReorgType::ChangeOrder) => { + broadcast_tx_and_mine(&txs[1], INSTANCE_3); + broadcast_tx_and_mine(&txs[2], INSTANCE_3); + broadcast_tx_and_mine(&txs[0], INSTANCE_3); + wlt_1.switch_to_instance(INSTANCE_3); + wlt_2.switch_to_instance(INSTANCE_3); + let wlt_1_alloc_1 = 200; + let wlt_1_alloc_2 = 399; + let wlt_2_alloc_1 = 1; + wlt_1.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![wlt_1_alloc_1, wlt_1_alloc_2], + ); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt_2_alloc_1]); + } + (HistoryType::Merging, ReorgType::ChangeOrder) => { + broadcast_tx_and_mine(&txs[1], INSTANCE_3); + broadcast_tx_and_mine(&txs[0], INSTANCE_3); + broadcast_tx_and_mine(&txs[2], INSTANCE_3); + wlt_1.switch_to_instance(INSTANCE_3); + wlt_2.switch_to_instance(INSTANCE_3); + let wlt_1_alloc_1 = 599; + let wlt_2_alloc_1 = 1; + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt_1_alloc_1]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt_2_alloc_1]); + } + (HistoryType::Merging, ReorgType::Revert) => { + broadcast_tx_and_mine(&txs[1], INSTANCE_3); + broadcast_tx_and_mine(&txs[2], INSTANCE_3); + wlt_1.switch_to_instance(INSTANCE_3); + wlt_2.switch_to_instance(INSTANCE_3); + let wlt_1_alloc_1 = 400; + let wlt_2_alloc_1 = 200; + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt_1_alloc_1]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt_2_alloc_1]); + } + } + + let tx_0_instance_3_height = get_tx_height(txs[0].txid(), INSTANCE_3); + let tx_1_instance_3_height = get_tx_height(txs[1].txid(), INSTANCE_3); + let tx_2_instance_3_height = get_tx_height(txs[2].txid(), INSTANCE_3); + + dbg!( + &txs[0].txid(), + tx_0_instance_2_height, + tx_0_instance_3_height + ); + dbg!( + &txs[1].txid(), + tx_1_instance_2_height, + tx_1_instance_3_height + ); + dbg!( + &txs[2].txid(), + tx_2_instance_2_height, + tx_2_instance_3_height + ); + mine_custom(false, INSTANCE_3, 3); + connect_reorg_nodes(); + dbg!("final"); + wlt_1.switch_to_instance(INSTANCE_2); + wlt_2.switch_to_instance(INSTANCE_2); + + dbg!(wlt_1.runtime().state_own(contract_id).owned); + dbg!(wlt_2.runtime().state_own(contract_id).owned); + + // Verify final state based on history type + match history_type { + HistoryType::Linear => { + let wlt_1_alloc_1 = 10; + let wlt_1_alloc_2 = 20; + let wlt_1_amt = wlt_1_alloc_1 + wlt_1_alloc_2; + let wlt_2_alloc_1 = 490; + let wlt_2_alloc_2 = 80; + let wlt_2_amt = wlt_2_alloc_1 + wlt_2_alloc_2; + wlt_1.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![wlt_1_alloc_1, wlt_1_alloc_2], + ); + wlt_2.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![wlt_2_alloc_1, wlt_2_alloc_2], + ); + + // Test spending the final allocations + wlt_1.send( + &mut wlt_3, + false, + contract_id, + wlt_1_amt, + 1000, + None, + None, + None, + ); + wlt_2.send( + &mut wlt_3, + false, + contract_id, + wlt_2_amt, + 1000, + None, + None, + None, + ); + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + wlt_3.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt_1_amt, wlt_2_amt]); + } + HistoryType::Branching => { + let wlt_1_alloc_1 = 200; + let wlt_1_alloc_2 = 399; + let wlt_1_amt = wlt_1_alloc_1 + wlt_1_alloc_2; + let wlt_2_alloc_1 = 1; + wlt_1.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![wlt_1_alloc_1, wlt_1_alloc_2], + ); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt_2_alloc_1]); + + wlt_1.send( + &mut wlt_3, + false, + contract_id, + wlt_1_amt, + 1000, + None, + None, + None, + ); + wlt_2.send( + &mut wlt_3, + false, + contract_id, + wlt_2_alloc_1, + 1000, + None, + None, + None, + ); + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + wlt_3.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![wlt_1_amt, wlt_2_alloc_1], + ); + } + HistoryType::Merging => { + let wlt_1_alloc_1 = 599; + let wlt_2_alloc_1 = 1; + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt_1_alloc_1]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt_2_alloc_1]); + + wlt_1.send( + &mut wlt_3, + false, + contract_id, + wlt_1_alloc_1, + 1000, + None, + None, + None, + ); + wlt_2.send( + &mut wlt_3, + false, + contract_id, + wlt_2_alloc_1, + 1000, + None, + None, + None, + ); + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + wlt_3.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![wlt_1_alloc_1, wlt_2_alloc_1], + ); + } + } +} + +#[test] +#[serial] +fn revert_transfer_state() { + initialize(); + // connecting before disconnecting since disconnect is not idempotent + connect_reorg_nodes(); + disconnect_reorg_nodes(); + + let mut wlt = get_wallet_custom(&DescriptorType::Wpkh, INSTANCE_2); + let mut recv_wlt = get_wallet_custom(&DescriptorType::Wpkh, INSTANCE_2); + + let issued_supply = 600; + let utxo = wlt.get_utxo(None); + + // Create and issue NIA asset + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", issued_supply); + params.add_allocation(utxo, issued_supply); + let contract_id = wlt.issue_nia_with_params(params); + wlt.send_contract("TestAsset", &mut recv_wlt); + recv_wlt.reload_runtime(); + + wlt.check_allocations(contract_id, AssetSchema::RGB20, vec![issued_supply]); + + let amt = 200; + + wlt.send( + &mut recv_wlt, + false, + contract_id, + amt, + 1000, + None, + None, + None, + ); + wlt.check_allocations(contract_id, AssetSchema::RGB20, vec![issued_supply - amt]); + + mine_custom(false, INSTANCE_2, 1); + wlt.sync(); + recv_wlt.sync(); + + let state = recv_wlt.runtime().state_own(contract_id).owned; + let witness_status = state.values().next().unwrap().iter().next().unwrap().status; + dbg!(state, witness_status); + assert!(matches!(witness_status, WitnessStatus::Mined(_))); + + recv_wlt.switch_to_instance(INSTANCE_3); + let state = recv_wlt.runtime().state_own(contract_id).owned; + let archived = state.values().next().unwrap().is_empty(); + dbg!(state, archived); + assert!(archived); + recv_wlt.check_allocations(contract_id, AssetSchema::RGB20, vec![]); +} + +#[test] +#[ignore = "fix needed"] +fn mainnet_wlt_receiving_test_asset() { + initialize(); + + let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); + // FIXME: Because the latest `Mound` structure in rgb does not support setting the mainnet, + // The default `Mound.testnet` is eq true, which cannot correctly initialize the mainnet wallet, + // So this test case cannot be executed temporarily + let mut wlt_2 = get_mainnet_wallet(); + + // Create and issue NIA asset + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", 700); + let outpoint = wlt_1.get_utxo(None); + params.add_allocation(outpoint, 700); + let contract_id = wlt_1.issue_nia_with_params(params); + + let utxo = + Outpoint::from_str("bebcfcb200a17763f6932a6d6fca9448a4b46c5b737cc3810769a7403ef79ce6:0") + .unwrap(); + let invoice = wlt_2.invoice(contract_id, 150, false, None, Some(utxo)); + + let (consignment, tx, _) = wlt_1.transfer(invoice.clone(), None, Some(500), true, None); + wlt_1.mine_tx(&tx.txid(), false); + match wlt_2.accept_transfer(&consignment, None) { + Err(e) => { + dbg!(e.to_string()); + } + _ => panic!("validation must fail"), + } +} + +#[rstest] +#[case(TT::Blinded)] +#[case(TT::Witness)] +#[serial] +fn invoice_reuse(#[case] transfer_type: TransferType) { + println!("transfer_type {transfer_type:?}"); + + initialize(); + + let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); + wlt_1.set_coinselect_strategy(CustomCoinselectStrategy::TrueSmallSize); + let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); + + // Create and issue assets + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", 900); + params.add_allocation(wlt_1.get_utxo(None), 500); + params.add_allocation(wlt_1.get_utxo(None), 400); + let contract_id = wlt_1.issue_nia_with_params(params); + wlt_1.send_contract("TestAsset", &mut wlt_2); + wlt_2.reload_runtime(); + + let amount = 300; + // Create invoice + let invoice = wlt_2.invoice(contract_id, amount, false, None, None); + + // First use invoice + wlt_1.send_to_invoice(&mut wlt_2, invoice.clone(), Some(500), None, None); + + // Second use same invoice + let (_, _, _) = wlt_1.send_to_invoice(&mut wlt_2, invoice, Some(600), None, None); + + // Check asset allocations + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![100, 200]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![amount, amount]); +} + +#[rstest] +#[case(TT::Blinded)] +#[case(TT::Witness)] +fn pay_one_invoice_twice(#[case] transfer_type: TransferType) { + initialize(); + + let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); + let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); + + let issue_supply = 2000; + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", issue_supply); + let outpoint = wlt_1.get_utxo(None); + params.add_allocation(outpoint, issue_supply); + + let contract_id = wlt_1.issue_nia_with_params(params); + + let amount = 100; + let wout = match transfer_type { + TransferType::Blinded => false, + TransferType::Witness => true, + }; + + wlt_1.send_contract("TestAsset", &mut wlt_2); + wlt_2.reload_runtime(); + let invoice = wlt_2.invoice(contract_id, amount, wout, None, None); + + wlt_1.sync(); + + let (consignment, tx, _payment) = wlt_1.transfer(invoice.clone(), None, Some(1000), true, None); + let (consignment2, tx2, _paytment2) = wlt_1.transfer(invoice, None, Some(1000), true, None); + + wlt_1.sync(); + + wlt_1.mine_tx(&tx.txid(), false); + let _ = wlt_2.accept_transfer(&consignment, None); + wlt_1.sync(); + + wlt_1.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![issue_supply - amount - amount], + ); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![amount]); + + println!("first transfer complete. sending second one"); + + wlt_1.sync(); + + wlt_1.mine_tx(&tx2.txid(), false); + wlt_2.sync(); + let _ = wlt_2.accept_transfer(&consignment2, None); + wlt_1.sync(); + + wlt_1.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![issue_supply - amount - amount], + ); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![amount, amount]); +} + +#[test] +#[ignore = "fix needed"] +#[serial] +fn sync_mainnet_wlt() { + initialize(); + + // FIXME: Because the latest `Mound` structure in rgb does not support setting the mainnet, + // The default `Mound.testnet` is eq true, which cannot correctly initialize the mainnet wallet, + // So this test case cannot be executed temporarily + let mut wlt_1 = get_mainnet_wallet(); + + wlt_1.sync(); +} + +#[test] +#[serial] +fn receive_from_unbroadcasted_transfer_to_blinded() { + initialize(); + + let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); + let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); + let mut wlt_3 = get_wallet(&DescriptorType::Wpkh); + + // Create and issue assets + let mut params = NIAIssueParams::new("TestAsset", "TEST", "centiMilli", 600); + let utxo = wlt_1.get_utxo(None); + params.add_allocation(utxo, 600); + let contract_id = wlt_1.issue_nia_with_params(params); + wlt_1.send_contract("TestAsset", &mut wlt_2); + wlt_2.reload_runtime(); + wlt_1.send_contract("TestAsset", &mut wlt_3); + wlt_3.reload_runtime(); + + // Get UTXO and create invoice + let utxo = wlt_2.get_utxo(None); + + // In RGB v0.12, the invoice API has been changed + let invoice = wlt_2.invoice(contract_id, 100, false, None, Some(utxo)); + + // Create transfer but do not broadcast its TX + let (consignment, _tx, _) = wlt_1.transfer(invoice.clone(), None, Some(500), false, None); + wlt_2.accept_transfer(&consignment, None).unwrap(); + + // The following three lines are debug code, + // used to debug the transfer under normal broadcast logic + + // wlt_1.broadcast_tx(&tx); + // wlt_1.mine_tx(&tx.txid(), false); + // wlt_1.sync(); + + dbg!(wlt_2.runtime().state_own(contract_id).owned); + + let invoice = wlt_3.invoice(contract_id, 50, true, None, None); + // force stop sync, because the asset of wlt1 to wlt2 has not been on-chain, + // the transfer will execute sync, so it is impossible to transfer assets to wlt3 + wlt_2.set_force_stop_sync(true); + let (consignment, tx, _) = wlt_2.transfer(invoice, Some(2000), None, true, None); + wlt_2.mine_tx(&tx.txid(), false); + wlt_3.accept_transfer(&consignment, None).unwrap(); + let wlt_3_states = wlt_3.runtime().state_own(contract_id).owned; + let wlt_2_states = wlt_2.runtime().state_own(contract_id).owned; + dbg!(wlt_3_states, wlt_2_states); + dbg!(wlt_2.runtime().state_all(contract_id).owned); + dbg!(wlt_1.runtime().state_own(contract_id).owned); + dbg!(wlt_1.runtime().state_all(contract_id).owned); + + wlt_3.check_allocations(contract_id, AssetSchema::RGB20, vec![50]); + // This is the key point: + // Since the asset transfer from wlt1 to wlt2 was not broadcasted on-chain, + // when wlt2 transfers part of this asset to wlt3 and broadcasts it on-chain, + // after sync the transaction is invalid because the original witness information + // cannot be traced back to its source. The asset becoming invalid is expected behavior. + wlt_3.sync(); + wlt_3.check_allocations(contract_id, AssetSchema::RGB20, vec![]); +} + +#[test] +#[serial] +fn tr_multi_wallet_blind_transfers() { + initialize(); + + // Create three wallets using TR descriptor + let mut wlt_1 = get_wallet(&DescriptorType::Tr); + let mut wlt_2 = get_wallet(&DescriptorType::Tr); + let mut wlt_3 = get_wallet(&DescriptorType::Tr); + + // Issue NIA asset with 21 million supply + let circulating_supply = 21_000_000; + let mut params = NIAIssueParams::new( + "TestAssetMultiTransfer", + "TEST", + "centiMilli", + circulating_supply, + ); + let utxo = wlt_1.get_utxo(None); + params.add_allocation(utxo, circulating_supply); + let contract_id = wlt_1.issue_nia_with_params(params); + + // Send contract to other wallets + wlt_1.send_contract("TestAssetMultiTransfer", &mut wlt_2); + wlt_2.reload_runtime(); + wlt_1.send_contract("TestAssetMultiTransfer", &mut wlt_3); + wlt_3.reload_runtime(); + + // Transfer 120k from wallet 1 to wallet 2 using blind invoice + let wlt1_to_wlt2_amount = 120_000; + let invoice = wlt_2.invoice(contract_id, wlt1_to_wlt2_amount, false, None, None); + let (consignment, wlt1_to_wlt2_tx, _) = wlt_1.transfer(invoice, None, Some(1000), true, None); + wlt_2.accept_transfer(&consignment, None).unwrap(); + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt1_to_wlt2_amount]); + + // Check wallet states after first transfer (unconfirmed transaction state) + // wlt1 shows 0 available assets, wlt2 shows 120k available assets + println!("After Wallet 1 makes a payment to Wallet 2, the unconfirmed status of the witnessed transaction is not in the sync state"); + println!("wlt1_state: {:?}", wlt_1.get_allocation_sum(contract_id)); + println!("wlt2_state: {:?}", wlt_2.get_allocation_sum(contract_id)); + + // Transfer 100k from wallet 2 to wallet 3 using blind invoice + let wlt2_to_wlt3_amount = 100_000; + let invoice = wlt_3.invoice(contract_id, wlt2_to_wlt3_amount, false, None, None); + let (consignment, wlt2_to_wlt3_tx, _) = wlt_2.transfer(invoice, None, Some(1000), true, None); + wlt_3.accept_transfer(&consignment, None).unwrap(); + + wlt_1.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + wlt_3.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt2_to_wlt3_amount]); + + // Check wallet states after second transfer (unconfirmed transaction state) + // wlt2 shows 0 available assets, wlt3 shows 100k available assets + println!("After Wallet 2 makes a payment to Wallet 3, the unconfirmed status of the witnessed transaction is not in the sync state"); + println!("wlt2_state: {:?}", wlt_2.get_allocation_sum(contract_id)); + println!("wlt3_state: {:?}", wlt_3.get_allocation_sum(contract_id)); + + // Mine both transactions + wlt_1.mine_tx(&wlt1_to_wlt2_tx.txid(), false); + wlt_2.mine_tx(&wlt2_to_wlt3_tx.txid(), false); + + // Sync all wallets + wlt_1.sync(); + wlt_2.sync(); + wlt_3.sync(); + + // Verify final allocations after sync + wlt_1.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![circulating_supply - wlt1_to_wlt2_amount], + ); + wlt_2.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![wlt1_to_wlt2_amount - wlt2_to_wlt3_amount], + ); + wlt_3.check_allocations(contract_id, AssetSchema::RGB20, vec![wlt2_to_wlt3_amount]); + + // Print final wallet states after sync - all states should be correct + println!("After sync"); + println!("wlt1_state: {:?}", wlt_1.get_allocation_sum(contract_id)); + println!("wlt2_state: {:?}", wlt_2.get_allocation_sum(contract_id)); + println!("wlt3_state: {:?}", wlt_3.get_allocation_sum(contract_id)); +} + +#[test] +#[serial] +fn cross_transfer_unconfirmed_test() { + initialize(); + + // Create three wallets using TR descriptor + let mut wlt_a = get_wallet(&DescriptorType::Tr); + let mut wlt_b = get_wallet(&DescriptorType::Tr); + let mut wlt_c = get_wallet(&DescriptorType::Tr); + wlt_b.set_coinselect_strategy(CustomCoinselectStrategy::TrueSmallSize); + + // Issue NIA asset with 600 total supply, distributed across 2 UTXOs + let total_supply = 600; + let mut params = + NIAIssueParams::new("CrossTransferTestUSDT", "USDT", "centiMilli", total_supply); + + // A UTXO gets 300, B UTXO gets 300 + let utxo_a = wlt_a.get_utxo(None); + let utxo_b = wlt_b.get_utxo(None); + params.add_allocation(utxo_a, 300); + params.add_allocation(utxo_b, 300); + + let contract_id = wlt_a.issue_nia_with_params(params); + + // Send contract to other wallets + wlt_a.send_contract("CrossTransferTestUSDT", &mut wlt_b); + wlt_b.reload_runtime(); + wlt_a.send_contract("CrossTransferTestUSDT", &mut wlt_c); + wlt_c.reload_runtime(); + + // Initial state check: A has 300, B has 300, C has 0 + println!("=== Initial State ==="); + wlt_a.check_allocations(contract_id, AssetSchema::RGB20, vec![300]); + wlt_b.check_allocations(contract_id, AssetSchema::RGB20, vec![300]); + wlt_c.check_allocations(contract_id, AssetSchema::RGB20, vec![]); + + println!( + "A balance: {:?}, {:?}", + wlt_a.get_allocation_sum(contract_id), + wlt_a.get_allocation_tuple(contract_id) + ); + println!( + "B balance: {:?}, {:?}", + wlt_b.get_allocation_sum(contract_id), + wlt_b.get_allocation_tuple(contract_id) + ); + println!( + "C balance: {:?}, {:?}", + wlt_c.get_allocation_sum(contract_id), + wlt_c.get_allocation_tuple(contract_id) + ); + + // Step 1: A transfers 50 USDT to B (unconfirmed) + println!("\n=== Step 1: A -> B (50 USDT) ==="); + let a_to_b_amount = 50; + let invoice_b = wlt_b.invoice(contract_id, a_to_b_amount, false, None, None); + let (consignment_a_to_b, tx_a_to_b, _) = + wlt_a.transfer(invoice_b, None, Some(1000), true, None); + wlt_b.accept_transfer(&consignment_a_to_b, None).unwrap(); + + // Check state after A->B transfer (before confirmation) + println!("After A->B transfer (unconfirmed):"); + println!( + "A balance: {:?}, {:?}", + wlt_a.get_allocation_sum(contract_id), + wlt_a.get_allocation_tuple(contract_id) + ); + println!( + "B balance: {:?}, {:?}", + wlt_b.get_allocation_sum(contract_id), + wlt_b.get_allocation_tuple(contract_id) + ); + println!( + "C balance: {:?}, {:?}", + wlt_c.get_allocation_sum(contract_id), + wlt_c.get_allocation_tuple(contract_id) + ); + + // Expected: A should show 250 (300-50), B should show 350 (300+50), C should show 0 + // Note: In unconfirmed state, wallets might show different behavior + wlt_a.check_allocations(contract_id, AssetSchema::RGB20, vec![]); // A shows 0 in unconfirmed state + wlt_b.check_allocations(contract_id, AssetSchema::RGB20, vec![300, 50]); // B shows original 300 + received 50 + + // Step 2: B transfers 51 USDT to C (while A->B is still unconfirmed) + println!("\n=== Step 2: B -> C (51 USDT) while A->B unconfirmed ==="); + let b_to_c_amount = 51; + let invoice_c = wlt_c.invoice(contract_id, b_to_c_amount, false, None, None); + let (consignment_b_to_c, tx_b_to_c, _) = + wlt_b.transfer(invoice_c, None, Some(1000), true, None); + wlt_c.accept_transfer(&consignment_b_to_c, None).unwrap(); + + // Check state after B->C transfer (both transactions unconfirmed) + println!("After B->C transfer (tx_b_to_c unconfirmed):"); + println!( + "A balance: {:?}, {:?}", + wlt_a.get_allocation_sum(contract_id), + wlt_a.get_allocation_tuple(contract_id) + ); + println!( + "B balance: {:?}, {:?}", + wlt_b.get_allocation_sum(contract_id), + wlt_b.get_allocation_tuple(contract_id) + ); + println!( + "C balance: {:?}, {:?}", + wlt_c.get_allocation_sum(contract_id), + wlt_c.get_allocation_tuple(contract_id) + ); + + // Check the potential BUG: B's original 300 USDT might disappear + wlt_a.check_allocations(contract_id, AssetSchema::RGB20, vec![]); // A shows 0 + wlt_b.check_allocations(contract_id, AssetSchema::RGB20, vec![50]); // B shows 50 + wlt_c.check_allocations(contract_id, AssetSchema::RGB20, vec![51]); // C shows 51 + + // Step 3: Mine both transactions to confirm them + println!("\n=== Step 3: Mining transactions ==="); + wlt_a.mine_tx(&tx_a_to_b.txid(), false); + wlt_b.mine_tx(&tx_b_to_c.txid(), false); + + // Step 4: Sync all wallets + println!("\n=== Step 4: Syncing wallets ==="); + wlt_a.sync(); + wlt_b.sync(); + wlt_c.sync(); + + // Final state check after confirmation and sync + println!("\n=== Final State (after confirmation and sync) ==="); + println!( + "A balance: {:?}, {:?}", + wlt_a.get_allocation_sum(contract_id), + wlt_a.get_allocation_tuple(contract_id) + ); + println!( + "B balance: {:?}, {:?}", + wlt_b.get_allocation_sum(contract_id), + wlt_b.get_allocation_tuple(contract_id) + ); + println!( + "C balance: {:?}, {:?}", + wlt_c.get_allocation_sum(contract_id), + wlt_c.get_allocation_tuple(contract_id) + ); + + // Expected final state: + // A: 300 - 50 = 250 + // B: 300 + 50 - 51 = 299 + // C: 0 + 51 = 51 + // Total should still be 600 + + // BUG reproduction: If the bug exists, B might only show 50 (from A) instead of 299 + println!("\n=== Verifying final allocations ==="); + wlt_a.check_allocations(contract_id, AssetSchema::RGB20, vec![250]); + + wlt_b.check_allocations(contract_id, AssetSchema::RGB20, vec![50, 249]); + + wlt_c.check_allocations(contract_id, AssetSchema::RGB20, vec![51]); + + // Verify total supply is conserved + let total_final = wlt_a.get_allocation_sum(contract_id) + + wlt_b.get_allocation_sum(contract_id) + + wlt_c.get_allocation_sum(contract_id); + assert_eq!( + total_final, total_supply, + "Total supply should be conserved" + ); + + println!( + "Total supply verification: {} == {}", + total_final, total_supply + ); + + if wlt_b.get_allocation_sum(contract_id) == 50 { + println!(" BUG DETECTED: Wallet B only shows 50 USDT instead of expected 320!"); + println!(" This indicates B's original 300 USDT disappeared during cross-transfer"); + } else { + println!(" No bug detected: Wallet B correctly shows expected balance"); + } +} + +#[rstest] +#[serial] +#[case(DT::Tr, CustomCoinselectStrategy::TrueSmallSize)] +#[case(DT::Wpkh, CustomCoinselectStrategy::TrueSmallSize)] +#[case( + DT::Tr, + CustomCoinselectStrategy::Standard(CoinselectStrategy::Aggregate) +)] +#[case( + DT::Wpkh, + CustomCoinselectStrategy::Standard(CoinselectStrategy::Aggregate) +)] +fn spend_from_utxo_with_multiple_allocations( + #[case] descriptor_type: DescriptorType, + #[case] coinselect_strategy: CustomCoinselectStrategy, +) { + initialize(); + + let mut wlt_1 = get_wallet(&descriptor_type); + let mut wlt_2 = get_wallet(&descriptor_type); + wlt_2.set_coinselect_strategy(coinselect_strategy); + let mut wlt_3 = get_wallet(&descriptor_type); + + println!("\n=== Test: spend_from_utxo_with_multiple_allocations ==="); + println!("Testing scenario: spending from UTXO with multiple confirmed allocations"); + + // 1. Preparation phase: Construct a state of "one UTXO, multiple allocations" + + // 1.1. wlt_1 issues the asset + let issue_supply = 1200; + let mut params = NIAIssueParams::new("ConsolidationTest", "CON", "centiMilli", issue_supply); + let outpoint = wlt_1.get_utxo(None); + params.add_allocation(outpoint, issue_supply); + let contract_id = wlt_1.issue_nia_with_params(params); + wlt_1.send_contract("ConsolidationTest", &mut wlt_2); + wlt_2.reload_runtime(); + wlt_1.send_contract("ConsolidationTest", &mut wlt_3); + wlt_3.reload_runtime(); + + println!("\n--- Phase 1.1: Asset issuance completed ---"); + println!("Issued {} tokens to wlt_1", issue_supply); + println!("Contract shared with wlt_2 and wlt_3"); + println!( + "wlt_1 initial balance: {}", + wlt_1.get_allocation_sum(contract_id) + ); + + // 1.2. wlt_2 obtains a specific UTXO to receive two payments + let receiving_utxo = wlt_2.get_utxo(None); + + println!("\n--- Phase 1.2: Receiving UTXO prepared ---"); + println!("wlt_2 receiving UTXO: {}", receiving_utxo); + + // 1.3. wlt_1 sends assets twice to the same UTXO of wlt_2 + // First send 800 + let invoice1 = wlt_2.invoice(contract_id, 800, false, None, Some(receiving_utxo)); + wlt_1.send_to_invoice(&mut wlt_2, invoice1, None, None, None); + + println!("\n--- Phase 1.3a: First transfer completed ---"); + println!("wlt_1 -> wlt_2: 800 tokens (confirmed)"); + println!("wlt_1 balance: {}", wlt_1.get_allocation_sum(contract_id)); + println!("wlt_2 balance: {}", wlt_2.get_allocation_sum(contract_id)); + for (addr, outpoint, amount, status) in wlt_2.get_allocation_tuple(contract_id) { + println!( + "wlt_2 addr: {}, outpoint: {}, amount: {}, status: {:?}", + addr, outpoint, amount, status + ); + } + + // Second send 200 to the exact same UTXO + let invoice2 = wlt_2.invoice(contract_id, 200, false, None, Some(receiving_utxo)); + wlt_1.send_to_invoice(&mut wlt_2, invoice2, None, None, None); + wlt_2.sync(); + + println!("\n--- Phase 1.3b: Second transfer completed ---"); + println!("wlt_1 -> wlt_2: 200 tokens (confirmed)"); + println!("wlt_1 balance: {}", wlt_1.get_allocation_sum(contract_id)); + println!("wlt_2 balance: {}", wlt_2.get_allocation_sum(contract_id)); + for (addr, outpoint, amount, status) in wlt_2.get_allocation_tuple(contract_id) { + println!( + "wlt_2 addr: {}, outpoint: {}, amount: {}, status: {:?}", + addr, outpoint, amount, status + ); + } + + // 1.4. Verify the initial state + // wlt_2 should now have two allocations on one UTXO, totaling 1000 + println!("\n--- Phase 1.4: Verifying initial state ---"); + wlt_2.check_allocations(contract_id, AssetSchema::RGB20, vec![800, 200]); + wlt_1.check_allocations( + contract_id, + AssetSchema::RGB20, + vec![issue_supply - 800 - 200], + ); // Change 200 + + println!("✓ wlt_2 has correct allocations: [800, 200]"); + println!( + "✓ wlt_1 has correct remaining balance: {}", + issue_supply - 800 - 200 + ); + + // 2. Action phase: wlt_2 spends part of the assets from this UTXO + + println!("\n--- Phase 2: Action phase - wlt_2 spending from multi-allocation UTXO ---"); + // wlt_2 sends 400 to wlt_3 + let amount_to_spend = 400; + println!("wlt_2 will send {} tokens to wlt_3", amount_to_spend); + println!( + "wlt_2 balance before spending: {}", + wlt_2.get_allocation_sum(contract_id) + ); + println!( + "wlt_3 balance before receiving: {}", + wlt_3.get_allocation_sum(contract_id) + ); + + wlt_2.send( + &mut wlt_3, + false, + contract_id, + amount_to_spend, + 1000, + None, + None, + None, + ); + + println!("\n--- Phase 2 completed: Transfer executed ---"); + println!( + "wlt_2 balance after spending: {}", + wlt_2.get_allocation_sum(contract_id) + ); + println!( + "wlt_3 balance after receiving: {}", + wlt_3.get_allocation_sum(contract_id) + ); + for (addr, outpoint, amount, status) in wlt_2.get_allocation_tuple(contract_id) { + println!( + "wlt_2 addr: {}, outpoint: {}, amount: {}, status: {:?}", + addr, outpoint, amount, status + ); + } + for (addr, outpoint, amount, status) in wlt_3.get_allocation_tuple(contract_id) { + println!( + "wlt_3 addr: {}, outpoint: {}, amount: {}, status: {:?}", + addr, outpoint, amount, status + ); + } + + // 3. Verification phase: Check if the results are correct + + println!("\n--- Phase 3: Verification phase ---"); + + // 3.1. wlt_3 should have received 400 + println!("Verifying wlt_3 received correct amount..."); + wlt_3.check_allocations(contract_id, AssetSchema::RGB20, vec![amount_to_spend]); + println!("✓ wlt_3 correctly received {} tokens", amount_to_spend); + + // 3.2. This is the most critical check: + // The change of wlt_2 should be 1000 - 400 = 600, and it should be a single merged allocation + let expected_change = 800 + 200 - amount_to_spend; + println!("\nCritical verification: wlt_2 change calculation"); + println!( + "Expected change: {} + {} - {} = {}", + 800, 200, amount_to_spend, expected_change + ); + + println!("\n--- Debug: wlt_2 owned state after spending ---"); + dbg!(wlt_2.runtime.state_own(contract_id).owned); + + println!("Verifying wlt_2 has correct remaining balance..."); + wlt_2.check_allocation_sum(contract_id, expected_change); + println!("✓ wlt_2 correctly has {} tokens remaining", expected_change); + + // Final verification: Total supply conservation + let total_final = wlt_1.get_allocation_sum(contract_id) + + wlt_2.get_allocation_sum(contract_id) + + wlt_3.get_allocation_sum(contract_id); + + println!("\n--- Final verification: Total supply conservation ---"); + println!( + "wlt_1 final balance: {}", + wlt_1.get_allocation_sum(contract_id) + ); + println!( + "wlt_2 final balance: {}", + wlt_2.get_allocation_sum(contract_id) + ); + println!( + "wlt_3 final balance: {}", + wlt_3.get_allocation_sum(contract_id) + ); + println!("Total final: {}", total_final); + println!("Original supply: {}", issue_supply); + + assert_eq!( + total_final, issue_supply, + "Total supply should be conserved" + ); + println!( + "✓ Total supply conservation verified: {} == {}", + total_final, issue_supply + ); + + println!("\n=== Test completed successfully ==="); +} diff --git a/tests/transfer_rgb21.rs b/tests/transfer_rgb21.rs new file mode 100644 index 0000000..99254f6 --- /dev/null +++ b/tests/transfer_rgb21.rs @@ -0,0 +1,162 @@ +pub mod utils; + +use ifaces::{EmbeddedMedia, MediaType, ProofOfReserves}; + +use rstest_reuse::{self, *}; +use std::str::FromStr; +use utils::{ + chain::initialize, + helper::wallet::{get_wallet, AssetSchema}, + DescriptorType, *, +}; + +#[template] +#[rstest] +#[case(true)] +#[case(false)] +fn wout(#[case] wout: bool) {} + +#[allow(dead_code)] +const MEDIA_FPATH: &str = "tests/fixtures/rgb_logo.jpeg"; + +#[apply(wout)] +#[ignore = "failed to issue contract: Inner(Genesis(Named(TypeName('DigitalCollection')), ScriptUnspecified))"] +fn simple_fac_transfer(wout: bool) { + initialize(); + + // Create two wallet instances + let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); + let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); + let total_fractions = 10_000; + let asset_name = "DigitalCollection"; + + // Create FAC asset parameters + let mut fac_params = FACIssueParams::new( + asset_name, + "A collection of digital assets", + total_fractions, + ); + + // Prepare NFT data + let ticker = "DCOLL"; + let name = "Digital Collection #1"; + + // Create preview data + let data = vec![1u8, 3u8, 9u8]; + let preview_ty = "image/jpeg"; + let token_data_preview = EmbeddedMedia { + mime: MediaType::with(preview_ty), + data: Confined::try_from(data.clone()).unwrap(), + }; + + // Create reserves proof + let proof = vec![2u8, 4u8, 6u8, 10u8]; + let token_data_reserves = ProofOfReserves { + utxo: Outpoint::from_str(FAKE_TXID).unwrap(), + proof: Confined::try_from(proof.clone()).unwrap(), + }; + + // Create attachment + let token_data_attachment = attachment_from_fpath(MEDIA_FPATH); + + // Create additional attachments + let mut token_data_attachments = BTreeMap::new(); + for (idx, attachment_fpath) in ["README.md", "Cargo.toml"].iter().enumerate() { + token_data_attachments.insert(idx as u8, attachment_from_fpath(attachment_fpath)); + } + + // Create NFT spec + let nft_spec = nft_spec( + name, + token_data_preview.clone(), + token_data_attachment.clone(), + token_data_reserves.clone(), + ); + + // Get an outpoint for allocation + let outpoint = wlt_1.get_utxo(None); + fac_params.with_allocation(outpoint, total_fractions); + fac_params.with_nft_spec(nft_spec); + + // Issue the contract + let contract_id = wlt_1.issue_fac_with_params(fac_params); + println!("FAC contract issued with ID: {}", contract_id); + + // Share contract with wallet 2 + wlt_1.send_contract(asset_name, &mut wlt_2); + wlt_2.reload_runtime(); + + // Verify initial state + let state = wlt_1.contract_state_rgb21(contract_id).unwrap(); + assert_eq!(state.immutable.name.as_str(), asset_name); + assert_eq!(state.immutable.total_fractions, total_fractions); + assert_eq!(state.owned.fractions.len(), 1); + assert_eq!(state.owned.fractions[0].1, total_fractions); + + dbg!(wlt_1.runtime().state_own(contract_id).owned); + dbg!(wlt_2.runtime().state_own(contract_id).owned); + + // Transfer some fractions to wallet 2 + let transfer_amount = 1001; + let invoice = wlt_2.invoice(contract_id, transfer_amount, wout, Some(0), None); + let (consignment_1, tx, _) = wlt_1.transfer(invoice, Some(9000), Some(500), true, None); + + // Receiver accepts the transfer + wlt_2.accept_transfer(&consignment_1, None).unwrap(); + + // Broadcast and confirm transaction + wlt_1.mine_tx(&tx.txid(), false); + + // Sync both wallets + wlt_1.sync(); + wlt_2.sync(); + + dbg!(wlt_1.runtime().state_own(contract_id).owned); + dbg!(wlt_2.runtime().state_own(contract_id).owned); + + // Verify allocations after transfer + wlt_1.check_allocations( + contract_id, + AssetSchema::RGB21, + vec![total_fractions - transfer_amount], + ); + wlt_2.check_allocations(contract_id, AssetSchema::RGB21, vec![transfer_amount]); + + // Check that NFT data is preserved in both wallets + let state_1 = wlt_1.contract_state_rgb21(contract_id).unwrap(); + let token_1 = state_1.immutable.token.unwrap(); + assert_eq!(token_1.ticker.unwrap().to_string(), ticker); + assert_eq!(token_1.name.unwrap().to_string(), name); + + let state_2 = wlt_2.contract_state_rgb21(contract_id).unwrap(); + let token_2 = state_2.immutable.token.unwrap(); + assert_eq!(token_2.ticker.unwrap().to_string(), ticker); + assert_eq!(token_2.name.unwrap().to_string(), name); + + // Test transferring some fractions back to wallet 1 + let return_amount = 1000; + let invoice = wlt_1.invoice(contract_id, return_amount, wout, Some(0), None); + let (consignment_2, tx, _) = wlt_2.transfer(invoice, Some(3000), Some(500), true, None); + + // Wallet 1 accepts the transfer + wlt_1.accept_transfer(&consignment_2, None).unwrap(); + + // Broadcast and confirm transaction + wlt_2.mine_tx(&tx.txid(), false); + + // Sync both wallets + wlt_1.sync(); + wlt_2.sync(); + + // Verify final allocations + wlt_1.check_allocations( + contract_id, + AssetSchema::RGB21, + vec![total_fractions - transfer_amount, return_amount], + ); + wlt_2.check_allocations( + contract_id, + AssetSchema::RGB21, + vec![transfer_amount - return_amount], + ); +} diff --git a/tests/transfers.rs b/tests/transfers.rs.bak similarity index 100% rename from tests/transfers.rs rename to tests/transfers.rs.bak diff --git a/tests/utils/chain.rs b/tests/utils/chain.rs index 5b0b276..9faaba6 100644 --- a/tests/utils/chain.rs +++ b/tests/utils/chain.rs @@ -1,9 +1,18 @@ use super::*; +use bpwallet::TxStatus; static INIT: Once = Once::new(); pub static INDEXER: OnceLock = OnceLock::new(); +// Node addresses +const NODE2_ADDR: &str = "172.30.2.205:18444"; +const NODE3_ADDR: &str = "172.30.2.206:18444"; +#[allow(dead_code)] +const NODE2_IP: &str = "172.30.2.205"; +#[allow(dead_code)] +const NODE3_IP: &str = "172.30.2.206"; + #[derive(Clone, Default, PartialEq, Eq, Debug)] pub enum Indexer { Electrum, @@ -27,21 +36,50 @@ pub fn initialize() { panic!("invalid indexer. possible values: `esplora` (default), `electrum`") } }); + if std::env::var("SKIP_INIT").is_ok() { println!("skipping services initialization"); return; } - let start_services_file = PathBuf::from("tests").join("start_services.sh"); + + let start_services_file = PathBuf::from("tests") + .join("docker") + .join("start_services.sh"); println!("starting test services..."); - let output = Command::new(start_services_file) - .env("PROFILE", INDEXER.get().unwrap().to_string()) + + let start_output = Command::new(&start_services_file) + .arg("start") .output() .expect("failed to start test services"); - if !output.status.success() { - println!("{output:?}"); + + if !start_output.status.success() { + println!("stdout: {}", String::from_utf8_lossy(&start_output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&start_output.stderr)); panic!("failed to start test services"); } - (INSTANCE_1..=INSTANCE_3).for_each(_wait_indexer_sync); + + // Wait for all nodes to be ready + for instance in INSTANCE_1..=INSTANCE_3 { + let mut attempts = 0; + let max_attempts = 30; + + loop { + if attempts >= max_attempts { + panic!("Node {instance} failed to start after {max_attempts} attempts"); + } + + let result = _bitcoin_cli_cmd(instance, vec!["getblockchaininfo"]); + if !result.is_empty() { + break; + } + + attempts += 1; + std::thread::sleep(Duration::from_secs(1)); + } + + // Wait for indexer sync + _wait_indexer_sync(instance); + } }); } @@ -61,35 +99,38 @@ fn _service_base_name() -> String { } fn _bitcoin_cli_cmd(instance: u8, args: Vec<&str>) -> String { - let compose_file = PathBuf::from("tests").join("docker-compose.yml"); + let compose_file = PathBuf::from("tests") + .join("docker") + .join("docker-compose.yml"); let mut bitcoin_cli = vec![ + s!("-p"), + s!("rgb-tests"), s!("-f"), compose_file.to_string_lossy().to_string(), s!("exec"), s!("-T"), ]; - let service_name = format!("{}_{instance}", _service_base_name()); - match INDEXER.get().unwrap() { - Indexer::Electrum => bitcoin_cli.extend(vec![ - "-u".to_string(), - "blits".to_string(), - service_name, - "bitcoin-cli".to_string(), - "-regtest".to_string(), - ]), - Indexer::Esplora => bitcoin_cli.extend(vec![service_name, "cli".to_string()]), - }; + + let service_name = format!("bitcoin-core-{instance}"); + bitcoin_cli.extend(vec![ + service_name, + "bitcoin-cli".to_string(), + "-regtest".to_string(), + ]); + let output = Command::new("docker") .stdin(Stdio::null()) .stderr(Stdio::null()) + .current_dir(PathBuf::from("tests").join("docker")) .arg("compose") .args(bitcoin_cli) .args(&args) .output() .unwrap_or_else(|_| panic!("failed to call bitcoind with args {args:?}")); + if !output.status.success() { println!("{output:?}"); - panic!("failed to get succesful output with args {args:?}"); + panic!("failed to get successful output with args {args:?}"); } String::from_utf8(output.stdout).unwrap().trim().to_string() } @@ -191,10 +232,9 @@ pub fn resume_mining() { } fn _get_connection_tuple() -> Vec<(u8, String)> { - let serive_base_name = _service_base_name(); vec![ - (INSTANCE_3, format!("{serive_base_name}_{INSTANCE_2}:18444")), - (INSTANCE_2, format!("{serive_base_name}_{INSTANCE_3}:18444")), + (INSTANCE_3, NODE2_ADDR.to_string()), // Node 2's address + (INSTANCE_2, NODE3_ADDR.to_string()), // Node 3's address ] } @@ -202,16 +242,21 @@ pub fn connect_reorg_nodes() { for (instance, node_addr) in _get_connection_tuple() { _bitcoin_cli_cmd(instance, vec!["addnode", &node_addr, "onetry"]); } + let t_0 = OffsetDateTime::now_utc(); + loop { - if (OffsetDateTime::now_utc() - t_0).as_seconds_f32() > 20.0 { - panic!("nodes are not syncing with each other") + if (OffsetDateTime::now_utc() - t_0).as_seconds_f32() > 60.0 { + panic!("nodes failed to sync after 60 seconds"); } + let height_2 = get_height_custom(INSTANCE_2); let height_3 = get_height_custom(INSTANCE_3); + if height_2 == height_3 { break; } + std::thread::sleep(Duration::from_millis(500)); } } @@ -220,6 +265,15 @@ pub fn disconnect_reorg_nodes() { for (instance, node_addr) in _get_connection_tuple() { _bitcoin_cli_cmd(instance, vec!["disconnectnode", &node_addr]); } + + for (instance, _) in _get_connection_tuple() { + // dump peer info + let peers = _bitcoin_cli_cmd(instance, vec!["getpeerinfo"]); + println!( + "disconnect_reorg_nodes:instance:{} peers: {}", + instance, peers + ); + } } pub fn get_height() -> u32 { @@ -232,6 +286,26 @@ pub fn get_height_custom(instance: u8) -> u32 { .expect("could not parse blockcount") } +pub fn get_tx_height(txid: Txid, instance: u8) -> Option { + match tx_status(txid, instance) { + TxStatus::Mined(info) => Some(info.height.into()), + _ => None, + } +} + +pub fn tx_status(txid: Txid, instance: u8) -> TxStatus { + match INDEXER.get().unwrap() { + Indexer::Esplora => EsploraClient::new_esplora(&indexer_url(instance, Network::Regtest)) + .unwrap() + .status(txid) + .unwrap(), + Indexer::Electrum => ElectrumClient::new(&indexer_url(instance, Network::Regtest)) + .unwrap() + .status(txid) + .unwrap(), + } +} + pub fn indexer_url(instance: u8, network: Network) -> String { match (INDEXER.get().unwrap(), network, instance) { (Indexer::Electrum, Network::Mainnet, _) => ELECTRUM_MAINNET_URL, @@ -287,3 +361,16 @@ pub fn fund_wallet(address: String, sats: Option, instance: u8) -> String { mine_custom(false, instance, 1); txid } + +pub fn get_raw_transaction(txid: &str, instance: u8) -> serde_json::Value { + let raw_tx = _bitcoin_cli_cmd(instance, vec!["getrawtransaction", txid, "true"]); + serde_json::from_str(&raw_tx).unwrap() +} + +pub fn is_tx_confirmed(txid: &str, instance: u8) -> bool { + let raw_tx = get_raw_transaction(txid, instance); + if raw_tx.get("confirmations").is_none() { + return false; + } + raw_tx.get("confirmations").unwrap().as_u64().unwrap() > 0 +} diff --git a/tests/utils/helper/asset_params.rs b/tests/utils/helper/asset_params.rs new file mode 100644 index 0000000..af313ff --- /dev/null +++ b/tests/utils/helper/asset_params.rs @@ -0,0 +1,183 @@ +use super::*; +use hypersonic::IssuerSpec; + +/// RGB Asset creation parameters builder +#[derive(Clone)] +pub struct AssetParamsBuilder { + params: CreateParams, +} + +impl AssetParamsBuilder { + /// Create a new builder instance for non-inflatable asset + pub fn default_nia() -> Self { + Self { + params: Self::from_file(NON_INFLATABLE_ASSET_TEMPLATE_PATH), + } + } + + /// Create a new builder instance for fractional unique asset + pub fn default_fua() -> Self { + Self { + params: Self::from_file(FRACTIONAL_UNIQUE_ASSET_TEMPLATE_PATH), + } + } + + /// Create a new builder instance for fractionable asset collection + pub fn default_fac() -> Self { + Self { + params: Self::from_file(FRACTIONABLE_ASSET_COLLECTION_TEMPLATE_PATH), + } + } + + /// Load parameters from YAML file + pub fn from_file>(path: P) -> CreateParams { + let file = File::open(path).expect("Unable to open file"); + let params: CreateParams = + serde_yaml::from_reader::<_, CreateParams>(file).expect(""); + params + } + + /// Set the contract template ID + pub fn codex_id(mut self, codex_id: CodexId) -> Self { + self.params.issuer = IssuerSpec::Latest(codex_id); + self + } + + /// Set the consensus type + pub fn consensus(mut self, consensus: Consensus) -> Self { + self.params.consensus = consensus; + self + } + + /// Set whether it is a test network + pub fn testnet(mut self, testnet: bool) -> Self { + self.params.testnet = testnet; + self + } + + /// Set the contract method name + pub fn method(mut self, method: &str) -> Self { + self.params.method = VariantName::from_str(method).unwrap(); + self + } + + /// Set the contract name + pub fn name(mut self, name: &str) -> Self { + self.params.name = TypeName::from_str(name).unwrap(); + self + } + + /// Update name state in global states + pub fn update_name_state(mut self, value: &str) -> Self { + if let Some(state) = self + .params + .global + .iter_mut() + .find(|s| s.name == "name".into()) + { + state.state.verified = value.into(); + } + self + } + + /// Update details state in global states + pub fn update_details_state(mut self, value: &str) -> Self { + if let Some(state) = self + .params + .global + .iter_mut() + .find(|s| s.name == "details".into()) + { + state.state.verified = StrictVal::Unit; + state.state.unverified = Some(value.into()); + } + self + } + + /// Update ticker state in global states + pub fn update_ticker_state(mut self, value: &str) -> Self { + if let Some(state) = self + .params + .global + .iter_mut() + .find(|s| s.name == "ticker".into()) + { + state.state.verified = value.into(); + } + self + } + + /// Update precision state in global states + pub fn update_precision_state(mut self, value: &str) -> Self { + if let Some(state) = self + .params + .global + .iter_mut() + .find(|s| s.name == "precision".into()) + { + state.state.verified = value.into(); + } + self + } + + /// Update circulating state in global states + /// circulating type is "RGBContract.Amount" eq u64 in rust + pub fn update_circulating_state(mut self, value: u64) -> Self { + if let Some(state) = self + .params + .global + .iter_mut() + .find(|s| s.name == "issued".into()) + { + state.state.verified = value.into(); + } + self + } + + /// Update owned state + pub fn update_owned_state(mut self, seal: Outpoint, val: u64) -> Self { + // check if owned state exists + if let Some(state) = self + .params + .owned + .iter_mut() + .find(|s| s.name == "owned".into()) + { + // if exists, update seal and data + state.state.seal = EitherSeal::Alt(seal); + state.state.data = val.into(); + } else { + // if not exists, create a new owned state + self.params.owned.push(NamedState { + name: "owned".into(), + state: Assignment { + seal: EitherSeal::Alt(seal), + data: val.into(), + }, + }); + } + self + } + + pub fn clear_owned_state(mut self) -> Self { + self.params.owned.clear(); + self + } + + /// Add owned state + pub fn add_owned_state(mut self, seal: Outpoint, val: u64) -> Self { + self.params.owned.push(NamedState { + name: "balance".into(), + state: Assignment { + seal: EitherSeal::Alt(seal), + data: val.into(), + }, + }); + self + } + + /// Build CreateParams instance + pub fn build(self) -> CreateParams { + self.params + } +} diff --git a/tests/utils/helper/asset_types.rs b/tests/utils/helper/asset_types.rs new file mode 100644 index 0000000..35314f1 --- /dev/null +++ b/tests/utils/helper/asset_types.rs @@ -0,0 +1,286 @@ +use super::*; + +/// Parameters for NIA (Non-Inflatable Asset) issuance +#[derive(Clone)] +pub struct NIAIssueParams { + pub name: String, + pub ticker: String, + pub precision: String, + pub circulating_supply: u64, + pub initial_allocations: Vec<(Outpoint, u64)>, +} + +impl Default for NIAIssueParams { + fn default() -> Self { + Self { + name: "USD Tether".to_string(), + ticker: "USDT".to_string(), + precision: "centiMilli".to_string(), + circulating_supply: 1_000_000, + initial_allocations: vec![], + } + } +} + +impl NIAIssueParams { + pub fn new( + name: impl Into, + ticker: impl Into, + precision: impl Into, + circulating_supply: u64, + ) -> Self { + Self { + name: name.into(), + ticker: ticker.into(), + precision: precision.into(), + circulating_supply, + initial_allocations: vec![], + } + } + + pub fn add_allocation(&mut self, outpoint: Outpoint, amount: u64) -> &mut Self { + self.initial_allocations.push((outpoint, amount)); + self + } +} + +/// RGB Contract State representation +#[derive(Debug)] +pub struct ContractState { + /// Immutable state of the contract + pub immutable: ContractImmutableState, + /// Ownership state of the contract + pub owned: ContractOwnedState, +} + +/// Contract's immutable state +#[derive(Debug)] +pub struct ContractImmutableState { + pub name: String, + pub ticker: String, + pub precision: String, + pub circulating_supply: u64, +} + +/// Contract's ownership state +#[derive(Debug)] +pub struct ContractOwnedState { + pub allocations: Vec<(TxoSeal, u64)>, +} + +/// Parameters for FUA (Fractional unique asset) issuance +#[derive(Clone)] +pub struct FUAIssueParams { + /// Asset name + pub name: String, + /// Asset details + pub details: String, + /// Decimal precision for the asset + pub precision: String, + /// Total circulating supply + pub circulating_supply: u64, + /// Initial token allocations (outpoint, amount) + pub initial_allocations: Vec<(Outpoint, u64)>, +} + +impl Default for FUAIssueParams { + fn default() -> Self { + Self { + name: "DemoFUA".to_string(), + details: "Demo FUA details".to_string(), + precision: "centiMilli".to_string(), + circulating_supply: 10_000, + initial_allocations: vec![], + } + } +} + +impl FUAIssueParams { + /// Create new CFA issuance parameters + pub fn new( + name: impl Into, + details: impl Into, + precision: impl Into, + circulating_supply: u64, + ) -> Self { + Self { + name: name.into(), + details: details.into(), + precision: precision.into(), + circulating_supply, + initial_allocations: vec![], + } + } + + /// Add a token allocation + pub fn add_allocation(&mut self, outpoint: Outpoint, amount: u64) -> &mut Self { + self.initial_allocations.push((outpoint, amount)); + self + } +} + +/// Parameters for FAC (Fractionable Asset Collection) issuance +#[derive(Clone)] +pub struct FACIssueParams { + /// Collection name + pub name: String, + /// Collection details + pub details: String, + /// Total number of fractions + pub total_fractions: u64, + /// Token index + pub index: u32, + /// Initial token allocation (outpoint, Nft) + pub initial_allocation: Option<(Outpoint, Nft)>, + /// NFT specification + pub nft_spec: Option, +} + +impl Default for FACIssueParams { + fn default() -> Self { + Self { + name: "FAC".to_string(), + details: "Demo FAC details".to_string(), + total_fractions: 10_000, + index: UDA_FIXED_INDEX, + initial_allocation: None, + nft_spec: None, + } + } +} + +impl FACIssueParams { + /// Create new FAC issuance parameters + pub fn new(name: impl Into, details: impl Into, total_fractions: u64) -> Self { + Self { + name: name.into(), + details: details.into(), + index: UDA_FIXED_INDEX, + total_fractions, + initial_allocation: None, + nft_spec: None, + } + } + + /// Set token allocation + pub fn with_allocation(&mut self, outpoint: Outpoint, amount: u64) -> &mut Self { + let nft = Nft::new(self.index, amount); + self.initial_allocation = Some((outpoint, nft)); + self + } + + /// Set NFT specification + pub fn with_nft_spec(&mut self, nft_spec: NftSpec) -> &mut Self { + self.nft_spec = Some(nft_spec); + self + } +} + +/// Create a minimal NFT spec with just index +pub fn nft_spec_minimal() -> NftSpec { + NftSpec { + name: None, + embedded: EmbeddedMedia { + mime: MediaType::with("text/plain"), + data: Default::default(), + }, + external: None, + reserves: None, + } +} + +/// Create a complete NFT spec with all details +pub fn nft_spec( + name: &str, + preview: EmbeddedMedia, + media: Attachment, + reserves: ProofOfReserves, +) -> NftSpec { + let mut nft_spec = nft_spec_minimal(); + nft_spec.embedded = preview; + nft_spec.external = Some(media); + nft_spec.reserves = Some(reserves); + nft_spec.name = Some(AssetName::try_from(name.to_string()).unwrap()); + nft_spec +} + +/// Function to create a file attachment from a file path +pub fn attachment_from_fpath(fpath: &str) -> Attachment { + let file_bytes = std::fs::read(fpath).unwrap(); + let file_hash: sha256::Hash = Hash::hash(&file_bytes[..]); + let digest = file_hash.to_byte_array().into(); + let mime = FileFormat::from_file(fpath) + .unwrap() + .media_type() + .to_string(); + let media_ty: &'static str = Box::leak(mime.clone().into_boxed_str()); + let media_type = MediaType::with(media_ty); + Attachment { + mime: media_type, + digest, + } +} + +/// Immutable state part of RGB21 contract +#[derive(Debug, Clone)] +pub struct RGB21ContractImmutableState { + pub name: String, + pub total_fractions: u64, + pub token: Option, +} + +/// NFT metadata in RGB21 contract +#[derive(Debug, Clone)] +pub struct NFTMetadata { + pub index: u32, + pub amount: u64, + pub ticker: Option, + pub name: Option, + pub details: Option, + pub preview: Option, + pub media: Option, + pub attachments: BTreeMap, + pub reserves: Option, +} + +/// Media data with full content +#[derive(Debug, Clone)] +pub struct MediaData { + pub media_type: MediaTypeData, + pub data: Vec, +} + +/// Media type information +#[derive(Debug, Clone)] +pub struct MediaTypeData { + pub r#type: String, + pub subtype: Option, + pub charset: Option, +} + +/// Media digest (reference only) +#[derive(Debug, Clone)] +pub struct MediaDigest { + pub media_type: MediaTypeData, + pub digest: Vec, +} + +/// Reserve proof data +#[derive(Debug, Clone)] +pub struct ReserveData { + pub utxo: Outpoint, + pub proof: Vec, +} + +/// Owned state part of RGB21 contract +#[derive(Debug, Clone)] +pub struct RGB21ContractOwnedState { + pub fractions: Vec<(Outpoint, u64)>, // (outpoint, amount) +} + +/// Complete RGB21 contract state +#[derive(Debug, Clone)] +pub struct RGB21ContractState { + pub immutable: RGB21ContractImmutableState, + pub owned: RGB21ContractOwnedState, +} diff --git a/tests/utils/helper/coinselect.rs b/tests/utils/helper/coinselect.rs new file mode 100644 index 0000000..8944382 --- /dev/null +++ b/tests/utils/helper/coinselect.rs @@ -0,0 +1,98 @@ +use super::*; + +/// Custom RGB coinselection strategy for more precise control over UTXO selection +/// +/// # Usage Example +/// +/// ``` +/// // Create wallet +/// let mut wallet = get_wallet(&DescriptorType::Wpkh); +/// +/// // Set to true small size strategy (selects UTXOs with maximum values) +/// wallet.set_coinselect_strategy(CustomCoinselectStrategy::TrueSmallSize); +/// +/// // Or use standard strategies +/// wallet.set_coinselect_strategy(CustomCoinselectStrategy::Standard(CoinselectStrategy::Aggregate)); +/// wallet.set_coinselect_strategy(CustomCoinselectStrategy::Standard(CoinselectStrategy::SmallSize)); +/// +/// // For transfers requiring specific UTXOs (like testing reorganization history), use: +/// let (consignment, tx) = wallet.transfer_with_specific_utxo(invoice, specific_utxo, sats, fee, broadcast, report); +/// ``` +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum CustomCoinselectStrategy { + /// Use standard RGB coinselection strategies + /// - Aggregate: Collects many small outputs until target amount is reached + /// - SmallSize: Collects minimum number of outputs but without proper value sorting + Standard(CoinselectStrategy), + + /// Enhanced coinselection strategy that truly minimizes transaction size + /// by selecting the minimum number of UTXOs with largest asset values. + /// This strategy: + /// 1. First sorts all available colored UTXOs by their asset amount + /// 2. Selects the minimum number of largest-value UTXOs needed to satisfy the transfer + /// 3. Results in smallest possible transaction size by using fewer inputs + TrueSmallSize, +} + +impl Default for CustomCoinselectStrategy { + fn default() -> Self { + Self::Standard(CoinselectStrategy::default()) + } +} + +/// Implementation of the Coinselect trait for our custom strategy +impl Coinselect for CustomCoinselectStrategy { + fn coinselect<'a>( + &mut self, + invoiced_state: &StrictVal, + calc: &mut StateCalc, + // Sorted vector by values + owned_state: impl IntoIterator< + Item = &'a OwnedState, + IntoIter: DoubleEndedIterator>, + >, + ) -> Option> { + match self { + // For standard strategies, delegate to the original implementation + CustomCoinselectStrategy::Standard(strategy) => { + strategy.coinselect(invoiced_state, calc, owned_state) + } + + // True small size implementation - sort by value before selection + CustomCoinselectStrategy::TrueSmallSize => { + // Clone the state to allow sorting (we need to own the data) + let mut value_sorted_state: Vec<(CellAddr, &StrictVal, u64, Outpoint)> = + owned_state + .into_iter() + .filter_map(|state| { + // Extract numeric value (assuming we're dealing with u64 values) + let val = &state.assignment.data; + let amount: u64 = val.unwrap_num().unwrap_uint(); + Some((state.addr, val, amount, state.assignment.seal)) + }) + .collect(); + + // Sort by value in descending order (largest first) + value_sorted_state.sort_by(|a, b| b.2.cmp(&a.2)); + + // Now use the sorted state for iteration + let res = value_sorted_state + .into_iter() + .take_while(|(_, val, _, _)| { + if calc.is_satisfied(invoiced_state) { + return false; + } + calc.accumulate(val).is_ok() + }) + .map(|(addr, _, _, outpoint)| (addr, outpoint)) + .collect(); + + if !calc.is_satisfied(invoiced_state) { + return None; + }; + + Some(res) + } + } + } +} diff --git a/tests/utils/helper/mod.rs b/tests/utils/helper/mod.rs new file mode 100644 index 0000000..dc9fb97 --- /dev/null +++ b/tests/utils/helper/mod.rs @@ -0,0 +1,7 @@ +pub mod asset_params; +pub mod asset_types; +pub mod coinselect; +pub mod reporting; +pub mod wallet; + +use super::*; diff --git a/tests/utils/helper/reporting.rs b/tests/utils/helper/reporting.rs new file mode 100644 index 0000000..1c3f2f1 --- /dev/null +++ b/tests/utils/helper/reporting.rs @@ -0,0 +1,464 @@ +use super::*; + +/// Test metric type +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum MetricType { + /// Duration (milliseconds) + Duration, + /// Bytes value + Bytes, + /// Integer value + Integer, + /// Float value + Float, + /// Text value + Text, +} + +/// Test metric definition +#[derive(Debug, Clone)] +pub struct MetricDefinition { + /// Metric name + pub name: String, + /// Metric type + pub metric_type: MetricType, + /// Metric description + pub description: String, +} + +/// Test report structure +pub struct Report { + /// Report file path + pub report_path: PathBuf, + /// Metric definitions + metrics: Vec, + /// File handle + file: Option, + /// Buffer for rows + buffer: Vec, + /// Current row being built + current_row: HashMap, + /// Buffer flush threshold + flush_threshold: usize, +} + +/// Report error types +#[derive(Debug)] +pub enum ReportError { + /// IO error + Io(std::io::Error), + /// Format error + Format(String), + /// Metric error + Metric(String), +} + +impl From for ReportError { + fn from(err: std::io::Error) -> Self { + ReportError::Io(err) + } +} + +impl std::fmt::Display for ReportError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ReportError::Io(err) => write!(f, "IO error: {}", err), + ReportError::Format(msg) => write!(f, "Format error: {}", msg), + ReportError::Metric(msg) => write!(f, "Metric error: {}", msg), + } + } +} + +impl std::error::Error for ReportError {} + +impl Report { + /// Create new report instance + pub fn new( + path: PathBuf, + metrics: Vec, + flush_threshold: Option, + ) -> Result { + let mut report = Self { + report_path: path, + metrics, + file: None, + buffer: Vec::new(), + current_row: HashMap::new(), + flush_threshold: flush_threshold.unwrap_or(10), + }; + + // Initialize report file + report.initialize()?; + + Ok(report) + } + + /// Initialize report file + fn initialize(&mut self) -> Result<(), ReportError> { + let headers: Vec = self.metrics.iter().map(|m| m.name.clone()).collect(); + + let file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(&self.report_path)?; + + let mut file = file; + file.write_all(format!("{}\n", headers.join(";")).as_bytes())?; + + // Save file handle for subsequent use + self.file = Some(file); + + Ok(()) + } + + /// Get file handle + fn get_file(&mut self) -> Result<&mut File, ReportError> { + if self.file.is_none() { + let file = OpenOptions::new().append(true).open(&self.report_path)?; + + self.file = Some(file); + } + + Ok(self.file.as_mut().unwrap()) + } + + /// Add duration metric by name + pub fn add_duration(&mut self, name: &str, duration: Duration) -> Result<(), ReportError> { + self.check_metric_name_and_type(name, MetricType::Duration)?; + self.current_row + .insert(name.to_string(), duration.as_millis().to_string()); + Ok(()) + } + + /// Add bytes metric by name + pub fn add_bytes(&mut self, name: &str, value: u64) -> Result<(), ReportError> { + self.check_metric_name_and_type(name, MetricType::Bytes)?; + self.current_row.insert(name.to_string(), value.to_string()); + Ok(()) + } + + /// Add integer metric by name + pub fn add_integer(&mut self, name: &str, value: u64) -> Result<(), ReportError> { + self.check_metric_name_and_type(name, MetricType::Integer)?; + self.current_row.insert(name.to_string(), value.to_string()); + Ok(()) + } + + /// Add float metric by name + pub fn add_float(&mut self, name: &str, value: f64) -> Result<(), ReportError> { + self.check_metric_name_and_type(name, MetricType::Float)?; + self.current_row.insert(name.to_string(), value.to_string()); + Ok(()) + } + + /// Add text metric by name + pub fn add_text(&mut self, name: &str, value: &str) -> Result<(), ReportError> { + self.check_metric_name_and_type(name, MetricType::Text)?; + self.current_row.insert(name.to_string(), value.to_string()); + Ok(()) + } + + /// Add arbitrary type metric by name (auto conversion) + pub fn add_value(&mut self, name: &str, value: T) -> Result<(), ReportError> { + if !self.metrics.iter().any(|m| m.name == name) { + return Err(ReportError::Metric(format!( + "Metric name '{}' not found", + name + ))); + } + + self.current_row.insert(name.to_string(), value.to_string()); + Ok(()) + } + + /// Helper method to check if metric name exists and has correct type + fn check_metric_name_and_type( + &self, + name: &str, + expected_type: MetricType, + ) -> Result<(), ReportError> { + let metric = self.metrics.iter().find(|m| m.name == name); + + match metric { + Some(m) if m.metric_type == expected_type => Ok(()), + Some(m) => Err(ReportError::Metric(format!( + "Metric '{}' type mismatch, expected {:?}, actual {:?}", + name, expected_type, m.metric_type + ))), + None => Err(ReportError::Metric(format!( + "Metric name '{}' not found", + name + ))), + } + } + + /// Complete current row and add to buffer + pub fn end_row(&mut self) -> Result<(), ReportError> { + // Ensure all metrics have values + for metric in &self.metrics { + if !self.current_row.contains_key(&metric.name) { + self.current_row.insert(metric.name.clone(), String::new()); + } + } + + // Create row in the same order as metrics + let row = self + .metrics + .iter() + .map(|m| self.current_row.get(&m.name).cloned().unwrap_or_default()) + .collect::>() + .join(";"); + + self.buffer.push(row); + + // Clear current row for next use + self.current_row.clear(); + + // If buffer reaches threshold, flush to file + if self.buffer.len() >= self.flush_threshold { + self.flush_buffer()?; + } + + Ok(()) + } + + /// Write buffer content to file + pub fn flush_buffer(&mut self) -> Result<(), ReportError> { + if self.buffer.is_empty() { + return Ok(()); + } + + // Clone buffer contents to avoid borrow conflict + let buffer_contents = self.buffer.clone(); + let file = self.get_file()?; + + for row in buffer_contents.iter() { + file.write_all(format!("{}\n", row).as_bytes())?; + } + + self.buffer.clear(); + + Ok(()) + } + + /// Generate summary statistics + pub fn generate_summary(&mut self) -> Result { + // Ensure all data is written to file + self.flush_buffer()?; + + // Read CSV file + let content = std::fs::read_to_string(&self.report_path)?; + let lines: Vec<&str> = content.lines().collect(); + + if lines.is_empty() { + return Err(ReportError::Format("CSV file is empty".to_string())); + } + + // Parse headers + let headers: Vec<&str> = lines[0].split(';').collect(); + + // Prepare data structure + let mut data: Vec> = vec![Vec::new(); headers.len()]; + + // Parse data rows + for line in lines.iter().skip(1) { + let values: Vec<&str> = line.split(';').collect(); + for (i, value) in values.iter().enumerate() { + if i >= headers.len() { + break; + } + + if let Ok(num) = value.parse::() { + data[i].push(num); + } + } + } + + #[derive(Tabled)] + struct MetricSummary { + #[tabled(rename = "Metric")] + metric: String, + #[tabled(rename = "Average")] + average: String, + #[tabled(rename = "Minimum")] + minimum: String, + #[tabled(rename = "Maximum")] + maximum: String, + #[tabled(rename = "Sample Count")] + count: String, + } + + let mut summaries = Vec::new(); + + for (i, header) in headers.iter().enumerate() { + if data[i].is_empty() { + continue; + } + + let values = &data[i]; + let avg = values.iter().sum::() / values.len() as f64; + let min = values.iter().fold(f64::INFINITY, |a, &b| a.min(b)); + let max = values.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b)); + + // Format output based on metric type + let metric_type = if i < self.metrics.len() { + self.metrics[i].metric_type + } else { + MetricType::Float + }; + + let (avg_str, min_str, max_str) = match metric_type { + MetricType::Duration => ( + format!("{:.2} ms", avg), + format!("{:.2} ms", min), + format!("{:.2} ms", max), + ), + MetricType::Bytes => ( + format!("{:.2} B", avg), + format!("{:.2} B", min), + format!("{:.2} B", max), + ), + MetricType::Integer | MetricType::Float => ( + format!("{:.2}", avg), + format!("{:.2}", min), + format!("{:.2}", max), + ), + MetricType::Text => ("-".to_string(), "-".to_string(), "-".to_string()), + }; + + summaries.push(MetricSummary { + metric: header.to_string(), + average: avg_str, + minimum: min_str, + maximum: max_str, + count: values.len().to_string(), + }); + } + + // Create the table and style it + let mut table = Table::new(summaries); + table + .with(Style::markdown()) + .with(Modify::new(Columns::new(1..)).with(Alignment::right())); + + // Generate the final Markdown output + let mut summary = String::new(); + summary.push_str("# Performance Test Summary\n\n"); + summary.push_str(&table.to_string()); + + Ok(summary) + } + + /// Save summary statistics to file + pub fn save_summary(&mut self, name: &str) -> Result { + let summary = self.generate_summary()?; + + let summary_path = self + .report_path + .clone() + .with_file_name(format!("{}.md", name)); + + let mut file = std::fs::File::create(&summary_path)?; + file.write_all(summary.as_bytes())?; + + Ok(summary_path) + } + + /// Generate chart data + pub fn generate_chart_data(&mut self) -> Result { + // Ensure all data is written to file + self.flush_buffer()?; + + // Read CSV file + let content = std::fs::read_to_string(&self.report_path)?; + let lines: Vec<&str> = content.lines().collect(); + + if lines.is_empty() { + return Err(ReportError::Format("CSV file is empty".to_string())); + } + + // Parse headers + let headers: Vec<&str> = lines[0].split(';').collect(); + + // Prepare data structure + let mut data: Vec> = vec![Vec::new(); headers.len()]; + + // Parse data rows + for line in lines.iter().skip(1) { + let values: Vec<&str> = line.split(';').collect(); + for (i, value) in values.iter().enumerate() { + if i >= headers.len() { + break; + } + + if let Ok(num) = value.parse::() { + data[i].push(num); + } + } + } + + // Generate JSON + let mut json = String::from("{\n"); + + for (i, header) in headers.iter().enumerate() { + if i > 0 { + json.push_str(",\n"); + } + + json.push_str(&format!(" \"{}\": [", header)); + + for (j, value) in data[i].iter().enumerate() { + if j > 0 { + json.push_str(", "); + } + json.push_str(&format!("{}", value)); + } + + json.push(']'); + } + + json.push_str("\n}"); + + // Save JSON + let mut chart_path = self.report_path.clone(); + chart_path.set_extension("json"); + + let mut file = std::fs::File::create(&chart_path)?; + file.write_all(json.as_bytes())?; + + Ok(chart_path) + } + + /// Ensure all data is written on drop + pub fn finalize(&mut self) -> Result<(), ReportError> { + self.flush_buffer() + } + + /// For backward compatibility + pub fn write_header(&self, _fields: &[&str]) { + // Do nothing, headers are now defined by metrics + } + + /// For backward compatibility + pub fn write_duration(&self, _duration: Duration) { + // Do nothing, use add_duration instead + } + + /// For backward compatibility + pub fn write_value(&self, _value: T) { + // Do nothing, use add_value instead + } + + /// For backward compatibility + pub fn end_line(&self) { + // Do nothing, use end_row instead + } +} + +impl Drop for Report { + fn drop(&mut self) { + // Try to flush buffer, ignore errors + let _ = self.flush_buffer(); + } +} diff --git a/tests/utils/helper/wallet.rs b/tests/utils/helper/wallet.rs new file mode 100644 index 0000000..c21a17d --- /dev/null +++ b/tests/utils/helper/wallet.rs @@ -0,0 +1,1627 @@ +use rgb::WitnessStatus; + +use super::*; + +enum WalletAccount { + Private(XprivAccount), + Public(XpubAccount), +} +/// Test wallet structure type +pub struct TestWallet { + /// RGB runtime for wallet operations + pub runtime: RgbpRuntimeDir, + /// RGB descriptor for wallet + pub descriptor: RgbDescr, + /// Signer for transaction signing + pub signer: Option, + /// Wallet directory path + pub wallet_dir: PathBuf, + /// Bitcoin node instance number + pub instance: u8, + /// Custom coinselection strategy + pub coinselect_strategy: CustomCoinselectStrategy, + /// Optional wallet identifier for reporting purposes + pub wallet_id: Option, + /// Whether to force stop sync + pub force_stop_sync: bool, +} + +pub enum AllocationFilter { + Stock, + Wallet, + WalletAll, + WalletTentative, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum DescriptorType { + Wpkh, + Tr, +} + +impl fmt::Display for DescriptorType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", format!("{:?}", self).to_lowercase()) + } +} + +#[derive(Debug, Copy, Clone)] +pub enum HistoryType { + Linear, + Branching, + Merging, +} + +#[derive(Debug, Copy, Clone)] +pub enum ReorgType { + ChangeOrder, + Revert, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum TransferType { + Blinded, + Witness, +} + +impl fmt::Display for TransferType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", format!("{:?}", self).to_lowercase()) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum InvoiceType { + Blinded(Option), + Witness, +} + +impl From for InvoiceType { + fn from(transfer_type: TransferType) -> Self { + match transfer_type { + TransferType::Blinded => InvoiceType::Blinded(None), + TransferType::Witness => InvoiceType::Witness, + } + } +} + +/// RGB asset-specific information to color a transaction +#[derive(Clone, Debug)] +pub struct AssetColoringInfo { + /// Contract iface + pub iface: TypeName, + /// Input outpoints of the assets being spent + pub input_outpoints: Vec, + /// Map of vouts and asset amounts to color the transaction outputs + pub output_map: HashMap, + /// Static blinding to keep the transaction construction deterministic + pub static_blinding: Option, +} + +/// RGB information to color a transaction +#[derive(Clone, Debug)] +pub struct ColoringInfo { + /// Asset-specific information + pub asset_info_map: HashMap, + /// Static blinding to keep the transaction construction deterministic + pub static_blinding: Option, + /// Nonce for offchain TXs ordering + pub nonce: Option, +} + +#[derive(Debug, EnumIter, Copy, Clone, PartialEq)] +pub enum AssetSchema { + RGB20, + RGB21, + RGB25, +} + +impl fmt::Display for AssetSchema { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", format!("{:?}", self).to_lowercase()) + } +} + +/// Create a new wallet with the specified descriptor type +pub fn get_wallet(descriptor_type: &DescriptorType) -> TestWallet { + get_wallet_custom(descriptor_type, INSTANCE_1) +} + +/// Create a new wallet with the specified descriptor type and instance +pub fn get_wallet_custom(descriptor_type: &DescriptorType, instance: u8) -> TestWallet { + let mut seed = vec![0u8; 128]; + rand::thread_rng().fill_bytes(&mut seed); + + let xpriv_account = XprivAccount::with_seed(true, &seed).derive(h![86, 1, 0]); + + let fingerprint = xpriv_account.account_fp().to_string(); + let wallet_dir = PathBuf::from(TEST_DATA_DIR) + .join(INTEGRATION_DATA_DIR) + .join(fingerprint); + + _get_wallet( + descriptor_type, + Network::Regtest, + wallet_dir, + WalletAccount::Private(xpriv_account), + instance, + ) +} + +/// Create a wallet for mainnet (using predefined public keys) +pub fn get_mainnet_wallet() -> TestWallet { + let xpub_account = XpubAccount::from_str( + "[c32338a7/86h/0h/0h]xpub6CmiK1xc7YwL472qm4zxeURFX8yMCSasioXujBjVMMzA3AKZr6KLQEmkzDge1Ezn2p43ZUysyx6gfajFVVnhtQ1AwbXEHrioLioXXgj2xW5" + ).unwrap(); + + let wallet_dir = PathBuf::from(TEST_DATA_DIR) + .join(INTEGRATION_DATA_DIR) + .join("mainnet"); + + _get_wallet( + &DescriptorType::Wpkh, + Network::Mainnet, + wallet_dir, + WalletAccount::Public(xpub_account), + INSTANCE_1, + ) +} + +/// Internal wallet creation function +fn _get_wallet( + descriptor_type: &DescriptorType, + network: Network, + wallet_dir: PathBuf, + wallet_account: WalletAccount, + instance: u8, +) -> TestWallet { + std::fs::create_dir_all(&wallet_dir).unwrap(); + println!("wallet dir: {wallet_dir:?}"); + + let xpub_account = match wallet_account { + WalletAccount::Private(ref xpriv_account) => xpriv_account.to_xpub_account(), + WalletAccount::Public(ref xpub_account) => xpub_account.clone(), + }; + let keychains: &[Keychain] = &[Keychain::INNER, Keychain::OUTER]; + let xpub_derivable = XpubDerivable::with(xpub_account.clone(), keychains); + let noise = xpub_derivable.xpub().chain_code().to_byte_array(); + + let descriptor = match descriptor_type { + DescriptorType::Wpkh => RgbDescr::new_unfunded(Wpkh::from(xpub_derivable), noise), + DescriptorType::Tr => RgbDescr::key_only_unfunded(xpub_derivable, noise), + }; + + let signer = match wallet_account { + WalletAccount::Private(xpriv_account) => Some(TestnetSigner::new(xpriv_account)), + WalletAccount::Public(_) => None, + }; + + let runtime = make_runtime(&descriptor, network, &wallet_dir); + let mut test_wallet = TestWallet { + runtime, + descriptor, + signer, + wallet_dir, + instance, + coinselect_strategy: CustomCoinselectStrategy::default(), + wallet_id: None, + force_stop_sync: false, + }; + + // Import all issuer files from the schemata directory + let issuer_dir = PathBuf::from(SCHEMATA_DIR); + if issuer_dir.exists() { + for entry in std::fs::read_dir(issuer_dir).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_file() && path.extension().is_some_and(|ext| ext == "issuer") { + // println!("Auto-importing issuer file: {}", path.display()); + if let Err(err) = test_wallet.import(path) { + println!("Warning: Failed to import issuer: {}", err); + } + } + } + } + + test_wallet.sync(); + + test_wallet +} + +pub fn contracts(network: Network, wallet_dir: PathBuf) -> Contracts> { + if !network.is_testnet() { + panic!("Non-testnet networks are not yet supported"); + } + let stockpile = StockpileDir::load(wallet_dir, Consensus::Bitcoin, true) + .expect("Invalid contracts directory"); + Contracts::load(stockpile) +} + +/// Create a runtime for the wallet +fn make_runtime( + descriptor: &RgbDescr, + network: Network, + wallet_dir: &PathBuf, +) -> RgbpRuntimeDir { + let name = "bp_wallet.wallet"; + let provider = FsTextStore::new(wallet_dir.join(name)).unwrap(); + + // Create wallet using Owner::create + let wallet = Owner::create(provider, descriptor.clone(), network, true) + .expect("Unable to create wallet"); + + let contracts = contracts(network, wallet_dir.clone()); + // Create runtime with wallet and contracts + let mut runtime = RgbpRuntimeDir::from(RgbWallet::with(wallet, contracts)); + let indexer = get_indexer(&indexer_url(INSTANCE_1, network)); + runtime + .sync(&indexer) + .expect("Unable to synchronize wallet"); + runtime +} + +/// Get an indexer instance +fn get_indexer(indexer_url: &str) -> AnyIndexer { + match INDEXER.get().unwrap() { + Indexer::Electrum => { + AnyIndexer::Electrum(Box::new(ElectrumClient::new(indexer_url).unwrap())) + } + Indexer::Esplora => { + AnyIndexer::Esplora(Box::new(EsploraClient::new_esplora(indexer_url).unwrap())) + } + } +} + +/// Broadcast a transaction +fn broadcast_tx(tx: &Tx, indexer_url: &str) { + match get_indexer(indexer_url) { + AnyIndexer::Electrum(inner) => { + inner.transaction_broadcast(tx).unwrap(); + } + AnyIndexer::Esplora(inner) => { + inner + .broadcast(tx) + .inspect_err(|e| { + dbg!( + tx.inputs.iter().map(|i| i.prev_output).collect::>(), + e + ); + }) + .unwrap(); + } + _ => unreachable!("unsupported indexer"), + } +} + +/// Broadcast a transaction and mine a block +pub fn broadcast_tx_and_mine(tx: &Tx, instance: u8) { + broadcast_tx(tx, &indexer_url(instance, Network::Regtest)); + mine_custom(false, instance, 1); +} + +impl TestWallet { + pub fn network(&self) -> Network { + self.runtime.wallet.network() + } + + pub fn testnet(&self) -> bool { + self.network().is_testnet() + } + + pub fn force_stop_sync(&self) -> bool { + self.force_stop_sync + } + + pub fn set_force_stop_sync(&mut self, force_stop_sync: bool) { + self.force_stop_sync = force_stop_sync; + } + + pub fn get_derived_address(&self) -> DerivedAddr { + self.runtime + .wallet + .addresses(Keychain::OUTER) + .next() + .expect("no addresses left") + } + + pub fn get_address(&self) -> Address { + self.get_derived_address().addr + } + + pub fn get_utxo(&mut self, sats: Option) -> Outpoint { + let address = self.get_address(); + let txid = Txid::from_str(&fund_wallet(address.to_string(), sats, self.instance)).unwrap(); + self.sync(); + let mut vout = None; + let coins = self.runtime.wallet.address_coins(); + assert!(!coins.is_empty()); + for (_derived_addr, utxos) in coins { + for utxo in utxos { + if utxo.outpoint.txid == txid { + vout = Some(utxo.outpoint.vout_u32()); + } + } + } + Outpoint { + txid, + vout: Vout::from_u32(vout.unwrap()), + } + } + + // TODO: Because the RGB mound currently cannot dynamically load contracts, + // It needs to be reloaded at a special time, and consider submitting a PR to RGB + pub fn reload_runtime(&mut self) { + self.runtime = make_runtime(&self.descriptor, self.network(), &self.wallet_dir); + self.sync(); + } + + pub fn change_instance(&mut self, instance: u8) { + self.instance = instance; + } + + pub fn issue_nia_with_params(&mut self, params: NIAIssueParams) -> ContractId { + let mut builder: AssetParamsBuilder = AssetParamsBuilder::default_nia() + .name(params.name.as_str()) + .update_name_state(params.name.as_str()) + .update_ticker_state(params.ticker.as_str()) + .update_precision_state(params.precision.as_str()) + .update_circulating_state(params.circulating_supply) + .clear_owned_state(); + + for (outpoint, amount) in params.initial_allocations { + builder = builder.add_owned_state(outpoint, amount); + } + + self.issue_with_params(builder.build()) + } + + /// Issue a FUA contract with custom parameters + pub fn issue_fua_with_params(&mut self, params: FUAIssueParams) -> ContractId { + let mut builder = AssetParamsBuilder::default_fua() + .name(params.name.as_str()) + .update_name_state(params.name.as_str()) + .update_details_state(params.details.as_str()) + .update_precision_state(params.precision.as_str()) + .update_circulating_state(params.circulating_supply) + .clear_owned_state(); + + // Add initial allocations + for (outpoint, amount) in params.initial_allocations { + builder = builder.add_owned_state(outpoint, amount); + } + + self.issue_with_params(builder.build()) + } + + pub fn switch_to_instance(&mut self, instance: u8) { + self.change_instance(instance); + self.sync(); + } + + pub fn indexer_url(&self) -> String { + indexer_url(self.instance, self.network()) + } + + fn get_indexer(&self) -> AnyIndexer { + get_indexer(&self.indexer_url()) + } + + pub fn broadcast_tx(&self, tx: &Tx) { + broadcast_tx(tx, &self.indexer_url()); + } + + pub fn sync(&mut self) { + if self.force_stop_sync { + return; + } + let indexer = self.get_indexer(); + self.runtime.sync(&indexer).expect("Failed to sync wallet"); + } + + pub fn runtime(&mut self) -> &mut RgbpRuntimeDir { + &mut self.runtime + } + + pub fn issue_with_params(&mut self, params: CreateParams) -> ContractId { + let contract_id = self + .runtime + .issue(params) + .expect("failed to issue a contract"); + println!("A new contract issued with ID {contract_id}"); + contract_id + } + + pub fn issue_from_file(&mut self, params_path: impl AsRef) -> ContractId { + let params = AssetParamsBuilder::from_file(params_path); + self.issue_with_params(params) + } + + pub fn mine_tx(&self, txid: &Txid, resume: bool) { + let mut attempts = 10; + loop { + mine_custom(resume, self.instance, 1); + if is_tx_confirmed(&txid.to_string(), self.instance) { + break; + } + attempts -= 1; + if attempts == 0 { + panic!("TX is not getting mined"); + } + } + } + + pub fn send_contract(&mut self, contract_name: &str, to_wallet: &mut TestWallet) { + let src_consensus_dir = self.wallet_dir.clone(); + let dst_consensus_dir = to_wallet.wallet_dir.clone(); + + let contract_id = self + .runtime + .contracts + .find_contract_id(TypeName::from_str(contract_name).unwrap()) + .expect("Contract not found"); + let contract_file_name = format!("{}.{:-}.contract", contract_name, contract_id); + let src_contract_dir = src_consensus_dir.join(&contract_file_name); + let dst_contract_dir = dst_consensus_dir.join(&contract_file_name); + std::fs::create_dir_all(&dst_contract_dir).unwrap(); + let read_dir = std::fs::read_dir(&src_contract_dir).unwrap(); + for entry in read_dir { + let entry = entry.unwrap(); + let path = entry.path(); + let dst_path = dst_contract_dir.join(path.file_name().unwrap()); + std::fs::copy(&path, &dst_path).unwrap(); + } + } + + /// Generates a noise engine for seal randomization + /// This is a clone of the internal noise_engine implementation from rgb-std, + /// since the original is not public and we need it for custom UTXO selection + fn noise_engine(&self) -> Sha256 { + let noise_seed = self.runtime.wallet.noise_seed(); + let mut noise_engine = Sha256::new(); + noise_engine.input_raw(noise_seed.as_ref()); + noise_engine + } + + /// Creates an auth token for a specific UTXO + /// + /// This is a custom implementation that allows specifying the UTXO to use, + /// unlike the standard rgb-std auth_token which automatically selects a UTXO. + /// We need this to support custom UTXO selection for auth tokens. + pub fn create_auth_token_with_utxo( + &mut self, + nonce: Option, + outpoint: Outpoint, + ) -> Option { + let nonce = nonce.unwrap_or_else(|| self.runtime.wallet.next_nonce()); + let seal = WTxoSeal::no_fallback(outpoint, self.noise_engine(), nonce); + let auth = seal.auth_token(); + self.runtime.wallet.register_seal(seal); + Some(auth) + } + + /// Creates an RGB invoice with either a witness output or auth token beneficiary + /// + /// # Arguments + /// * `contract_id` - ID of the RGB contract + /// * `amount` - Amount of RGB asset to transfer + /// * `wout` - Whether to use witness output (true) or auth token (false) + /// * `nonce` - Optional nonce for seal generation + /// * `utxo` - Optional UTXO to use for auth token. If None and wout=false, a new UTXO will be created + pub fn invoice( + &mut self, + contract_id: ContractId, + amount: u64, + wout: bool, + nonce: Option, + mut utxo: Option, + ) -> RgbInvoice { + let beneficiary = if wout { + let wout = self.runtime.wout(nonce); + RgbBeneficiary::WitnessOut(wout) + } else { + if utxo.is_none() { + // Create new UTXO for auth token if none provided + utxo = Some(self.get_utxo(None)); + } + + let auth = self.create_auth_token_with_utxo(nonce, utxo.unwrap()); + + RgbBeneficiary::Token(auth.unwrap()) + }; + let value = StrictVal::num(amount); + RgbInvoice::new( + contract_id, + Consensus::Bitcoin, + true, + beneficiary, + Some(value), + ) + } + + /// Set the coin selection strategy + pub fn set_coinselect_strategy(&mut self, strategy: CustomCoinselectStrategy) -> &mut Self { + self.coinselect_strategy = strategy; + self + } + + /// Get the current coin selection strategy + pub fn coinselect_strategy(&self) -> CustomCoinselectStrategy { + self.coinselect_strategy + } + + /// Set wallet identifier for reporting purposes + pub fn with_id(mut self, id: impl Into) -> Self { + self.wallet_id = Some(id.into()); + self + } + + /// Get wallet identifier, or a default if not set + pub fn wallet_id(&self) -> String { + self.wallet_id + .clone() + .unwrap_or_else(|| format!("wallet_{}", self.instance)) + } + + pub fn sign_finalize(&self, psbt: &mut Psbt) { + let _sig_count = psbt.sign(self.signer.as_ref().unwrap()).unwrap(); + psbt.finalize(self.runtime.wallet.descriptor()); + } + + pub fn sign_finalize_extract(&self, psbt: &mut Psbt) -> Tx { + self.sign_finalize(psbt); + psbt.extract().unwrap() + } + + pub fn check_allocations( + &mut self, + contract_id: ContractId, + asset_schema: AssetSchema, + mut expected_fungible_allocations: Vec, + ) { + let allocation_field = match asset_schema { + AssetSchema::RGB20 | AssetSchema::RGB25 => { + // For fungible assets, we need to check the "amount" allocation + "balance" + } + AssetSchema::RGB21 => { + // for RGB21, we need to check the "fractions" allocation + "balance" + } + }; + + let state = self.runtime.state_own(contract_id); + + let mut actual_fungible_allocations = state + .owned + .get(allocation_field) + .unwrap() + .iter() + .filter(|state| state.status.is_valid()) + .map(|state| state.assignment.data.unwrap_num().unwrap_uint::()) + .collect::>(); + actual_fungible_allocations.sort(); + expected_fungible_allocations.sort(); + assert_eq!(actual_fungible_allocations, expected_fungible_allocations); + } + + pub fn get_allocation_tuple( + &mut self, + contract_id: ContractId, + ) -> Vec<(String, String, u64, WitnessStatus)> { + let allocation_field = "balance"; + let state = self.runtime.state_own(contract_id); + state + .owned + .get(allocation_field) + .unwrap() + .iter() + .map(|state| { + ( + state.addr.to_string(), + state.assignment.seal.to_string(), + state.assignment.data.unwrap_num().unwrap_uint::(), + state.status, + ) + }) + .collect::>() + } + pub fn get_allocation_sum(&mut self, contract_id: ContractId) -> u64 { + let allocation_field = "balance"; + let state = self.runtime.state_own(contract_id); + state + .owned + .get(allocation_field) + .unwrap() + .iter() + .filter(|state| state.status.is_valid()) + .map(|state| state.assignment.data.unwrap_num().unwrap_uint::()) + .sum::() + } + + pub fn check_allocation_sum(&mut self, contract_id: ContractId, expected_sum: u64) { + let actual_allocation_sum = self.get_allocation_sum(contract_id); + assert_eq!(actual_allocation_sum, expected_sum); + } + + pub fn send( + &mut self, + recv_wallet: &mut TestWallet, + wout: bool, + contract_id: ContractId, + amount: u64, + sats: u64, + fee: Option, + nonce: Option, + report: Option<&mut Report>, + ) -> (PathBuf, Tx, Payment) { + let invoice = recv_wallet.invoice(contract_id, amount, wout, nonce, None); + self.send_to_invoice(recv_wallet, invoice, Some(sats), fee, report) + } + + pub fn send_to_invoice( + &mut self, + recv_wallet: &mut TestWallet, + invoice: RgbInvoice, + sats: Option, + fee: Option, + mut report: Option<&mut Report>, + ) -> (PathBuf, Tx, Payment) { + // We need to handle the report parameter carefully to avoid moving it + let transfer_report = report.as_deref_mut(); + + let (consignment, tx, payment) = self.transfer(invoice, sats, fee, true, transfer_report); + self.mine_tx(&tx.txid(), false); + // Now use the original report parameter + recv_wallet.accept_transfer(&consignment, report).unwrap(); + self.sync(); + (consignment, tx, payment) + } + + pub fn transfer( + &mut self, + invoice: RgbInvoice, + sats: Option, + fee: Option, + broadcast: bool, + report: Option<&mut Report>, + ) -> (PathBuf, Tx, Payment) { + self.sync(); + + let fee = Sats::from_sats(fee.unwrap_or(DEFAULT_FEE_ABS)); + let sats = Sats::from_sats(sats.unwrap_or(2000)); + + let strategy = self.coinselect_strategy; + let pay_start = Instant::now(); + let params = TxParams::with(fee); + let (psbt, payment) = self + .runtime + .pay_invoice(&invoice, strategy, params, Some(sats)) + .unwrap(); + + let pay_duration = pay_start.elapsed(); + + let (consignment, tx) = self.consign( + invoice.scope, + psbt.clone(), + &payment.terminals, + pay_duration, + broadcast, + report, + ); + (consignment, tx, payment) + } + + pub fn transfer_rbf( + &mut self, + contract_id: ContractId, + payment: Payment, + fee: u64, + report: Option<&mut Report>, + ) -> (PathBuf, Tx) { + let pay_start = Instant::now(); + let pay_duration = pay_start.elapsed(); + + // broadcast the transaction immediately after rbf execution, + // Wait for the old transaction to be archived, and then actively sync the wallet + let mut psbt = self.runtime.rbf(&payment, fee).unwrap(); + + let tx = self.sign_finalize_extract(&mut psbt); + + self.broadcast_tx(&tx); + std::thread::sleep(Duration::from_secs(10)); + self.sync(); + + let (consignment, tx) = self.consign( + contract_id, + psbt, + &payment.terminals, + pay_duration, + false, + report, + ); + (consignment, tx) + } + + fn consign<'a>( + &mut self, + contract_id: ContractId, + mut psbt: Psbt, + terminals: impl IntoIterator, + pay_duration: Duration, + broadcast: bool, + report: Option<&mut Report>, + ) -> (PathBuf, Tx) { + static COUNTER: OnceLock = OnceLock::new(); + let counter = COUNTER.get_or_init(|| AtomicU32::new(0)); + counter.fetch_add(1, Ordering::SeqCst); + let consignment_no = counter.load(Ordering::SeqCst); + + let tx = self.sign_finalize_extract(&mut psbt); + + println!( + "transfer txid: {}, consignment: {consignment_no}", + tx.txid() + ); + + if broadcast { + self.broadcast_tx(&tx); + } + + let consignment = self + .wallet_dir + .join(format!("consignment-{consignment_no}")) + .with_extension("rgb"); + + self.runtime + .contracts + .consign_to_file(&consignment, contract_id, terminals) + .unwrap(); + + if let Some(report) = report { + let wallet_id = self.wallet_id(); + let column_name = format!("{}_pay", wallet_id); + report.add_duration(&column_name, pay_duration).unwrap(); + + let consigment_column_name = format!("{}_pay_consignment_size", wallet_id); + let file_size = std::fs::metadata(&consignment).unwrap().len(); + report + .add_bytes(&consigment_column_name, file_size) + .unwrap(); + + let txin_column_name = format!("{}_pay_txin_count", wallet_id); + report + .add_integer(&txin_column_name, tx.inputs.len() as u64) + .unwrap(); + + let txout_column_name = format!("{}_pay_txout_count", wallet_id); + report + .add_integer(&txout_column_name, tx.outputs.len() as u64) + .unwrap(); + } + + (consignment, tx) + } + + pub fn accept_transfer( + &mut self, + consignment: &Path, + report: Option<&mut Report>, + ) -> Result<(), String> { + self.sync(); + let accept_start = Instant::now(); + self.runtime + .consume_from_file( + false, + consignment, + |_, _, _| Result::<_, Infallible>::Ok(()), + ) + .map_err(|e| format!("consume_from_file error: {}", e))?; + let accept_duration = accept_start.elapsed(); + if let Some(report) = report { + let column_name = format!("{}_accept", self.wallet_id()); + report.add_duration(&column_name, accept_duration).unwrap(); + } + Ok(()) + } + + /// Import an RGB schema(.issuer) file + /// + /// # Arguments + /// * `schema_path` - Path to the schema file to import + pub fn import(&mut self, schema_path: impl AsRef) -> Result<(), String> { + let schema_path = schema_path.as_ref(); + + // Check if file exists + if !schema_path.exists() { + return Err(format!( + "Schema file '{}' does not exist", + schema_path.display() + )); + } + + // print!( + // "Processing '{}' ... ", + // schema_path.file_name().unwrap().to_string_lossy() + // ); + + // Load schema and get codex ID + let issuer = Issuer::load(schema_path, |_, _, _| Result::<_, Infallible>::Ok(()))?; + let codex_id = issuer.codex_id(); + + // print!("codex id {} ... ", codex_id); + + // Import the schema into contracts + if self.runtime.contracts.has_issuer(codex_id) { + println!("already known, skipping"); + return Ok(()); + } + + self.runtime + .contracts + .import_issuer(issuer) + .map_err(|e| format!("import error: {}", e))?; + + Ok(()) + } +} + +impl TestWallet { + /// Get contract state with parsed data structures + pub fn contract_state(&mut self, contract_id: ContractId) -> Option { + self.contract_state_internal(contract_id) + .map(|(immutable, owned, _)| { + // Parse immutable state + let name = immutable + .get(&VariantName::from_str("name").unwrap()) + .and_then(|m| m.iter().next()) + .map(|v| v.data.verified.unwrap_string()) + .unwrap_or_default(); + + let ticker = immutable + .get(&VariantName::from_str("ticker").unwrap()) + .and_then(|m| m.iter().next()) + .map(|v| v.data.verified.unwrap_string()) + .unwrap_or_default(); + + let precision = immutable + .get(&VariantName::from_str("precision").unwrap()) + .and_then(|m| m.iter().next()) + .map(|v| { + let tag = v.data.verified.unwrap_enum_tag(); + if let EnumTag::Name(name) = tag { + name.to_string() + } else { + "".to_string() + } + }) + .unwrap_or_default(); + + let circulating_supply = immutable + .get(&VariantName::from_str("issued").unwrap()) + .and_then(|m: &Vec| m.iter().next()) + .map(|v| v.data.verified.unwrap_num().unwrap_uint::()) + .unwrap_or_default(); + + // Parse ownership state + let mut allocations = vec![]; + if let Some(owned_map) = owned.get(&VariantName::from_str("balance").unwrap()) { + for state in owned_map { + allocations.push(( + state.assignment.seal, + state.assignment.data.unwrap_num().unwrap_uint::(), + )); + } + } + + ContractState { + immutable: ContractImmutableState { + name, + ticker, + precision, + circulating_supply, + }, + owned: ContractOwnedState { allocations }, + } + }) + } + /// Get contract state (internal implementation) + fn contract_state_internal( + &mut self, + contract_id: ContractId, + ) -> Option<( + BTreeMap>, + BTreeMap>>, + BTreeMap, + )> { + let rgb_contract_state = self.runtime().state_all(contract_id); + + Some(( + rgb_contract_state.immutable, + rgb_contract_state.owned, + rgb_contract_state.aggregated, + )) + } +} + +/// Immutable state part of RGB21 contract +#[derive(Debug, Clone)] +pub struct RGB21ContractImmutableState { + pub name: String, + pub total_fractions: u64, + pub token: Option, +} + +/// NFT metadata in RGB21 contract +#[derive(Debug, Clone)] +pub struct NFTMetadata { + pub index: u32, + pub amount: u64, + pub ticker: Option, + pub name: Option, + pub details: Option, + pub preview: Option, + pub media: Option, + pub attachments: BTreeMap, + pub reserves: Option, +} + +/// Media data with full content +#[derive(Debug, Clone)] +pub struct MediaData { + pub media_type: MediaTypeData, + pub data: Vec, +} + +/// Media type information +#[derive(Debug, Clone)] +pub struct MediaTypeData { + pub r#type: String, + pub subtype: Option, + pub charset: Option, +} + +/// Media digest (reference only) +#[derive(Debug, Clone)] +pub struct MediaDigest { + pub media_type: MediaTypeData, + pub digest: Vec, +} + +/// Reserve proof data +#[derive(Debug, Clone)] +pub struct ReserveData { + pub utxo: Outpoint, + pub proof: Vec, +} + +/// Owned state part of RGB21 contract +#[derive(Debug, Clone)] +pub struct RGB21ContractOwnedState { + pub fractions: Vec<(TxoSeal, u64)>, // (outpoint, amount) +} + +/// Complete RGB21 contract state +#[derive(Debug, Clone)] +pub struct RGB21ContractState { + pub immutable: RGB21ContractImmutableState, + pub owned: RGB21ContractOwnedState, +} + +/// Extract the first element from a tuple +fn extract_from_tuple(v: &StrictVal) -> Option { + if let StrictVal::Tuple(s) = v { + if !s.is_empty() { + Some(s[0].clone()) + } else { + None + } + } else { + None + } +} + +/// Extract the first element from a two-layer tuple +fn extract_from_2_layer_tuple(v: &StrictVal) -> Option { + if let StrictVal::Tuple(t) = v { + if let Some(inner) = t.first() { + extract_from_tuple(inner) + } else { + None + } + } else { + None + } +} + +/// Extract value from Union (for Option type) +fn extract_from_union(v: &StrictVal) -> Option { + if let StrictVal::Union(tag, t) = v { + if let EnumTag::Name(name) = tag { + if ***name == "some" { + Some(t.as_ref().clone()) + } else { + None + } + } else { + None + } + } else { + None + } +} + +/// Extract value from Union and single-layer Tuple +fn extract_from_union_and_tuple(v: &StrictVal) -> Option { + extract_from_union(v).and_then(|s| extract_from_tuple(&s)) +} + +/// Extract value from Union and two-layer Tuple +fn extract_from_union_and_2_layer_tuple(v: &StrictVal) -> Option { + extract_from_union(v).and_then(|s| extract_from_2_layer_tuple(&s)) +} + +impl TestWallet { + // TODO: Need to optimize the following code + /// Issue a FAC contract with custom parameters + pub fn issue_fac_with_params(&mut self, params: FACIssueParams) -> ContractId { + let mut create_params = AssetParamsBuilder::default_fac() + .name(params.name.as_str()) + .update_name_state(params.name.as_str()) + .update_details_state(params.details.as_str()) + .build(); + + for name_state in create_params.global.iter_mut() { + let name = VariantName::from_str("token").unwrap(); + if name_state.name == name { + let token = &mut name_state.state.verified; + if let StrictVal::Struct(s) = token { + let reserved_name = FieldName::from_str("align").unwrap(); + let reserved = s.get_mut(&reserved_name).unwrap(); + *reserved = StrictVal::Bytes(Blob(vec![0; 26])); + + let index_name = FieldName::from_str("tokenIndex").unwrap(); + let index = s.get_mut(&index_name).unwrap(); + *index = StrictVal::Number(StrictNum::from(params.index)); + + let amount_name = FieldName::from_str("fraction").unwrap(); + let amount = s.get_mut(&amount_name).unwrap(); + *amount = StrictVal::Number(StrictNum::from(params.total_fractions)); + } + + if let Some(ref nft_spec) = params.nft_spec { + let nft_spec_strict_val = name_state.state.unverified.as_mut().unwrap(); + + match nft_spec_strict_val { + StrictVal::Struct(s) => { + let index_name = FieldName::from_str("index").unwrap(); + let index = s.get_mut(&index_name).unwrap(); + *index = StrictVal::Number(StrictNum::from(params.index)); + + if let Some(ref name_params) = nft_spec.name { + let name_name = FieldName::from_str("name").unwrap(); + let name = s.get_mut(&name_name).unwrap(); + *name = StrictVal::String(name_params.to_string()); + } + + let preview_params = &nft_spec.embedded; + let preview_name = FieldName::from_str("preview").unwrap(); + let preview = s.get_mut(&preview_name).unwrap(); + match preview { + StrictVal::Struct(s) => { + let preview_type_name = FieldName::from_str("type").unwrap(); + let preview_type = s.get_mut(&preview_type_name).unwrap(); + match preview_type { + StrictVal::Struct(ty) => { + let ty_name = FieldName::from_str("type").unwrap(); + let ty_type = ty.get_mut(&ty_name).unwrap(); + *ty_type = StrictVal::String( + preview_params.mime.ty.to_string(), + ); + + let subtype_name = + FieldName::from_str("subtype").unwrap(); + let subtype = ty.get_mut(&subtype_name).unwrap(); + + if let Some(ref subtype_params) = + preview_params.mime.subtype + { + *subtype = + StrictVal::String(subtype_params.to_string()); + } else { + *subtype = StrictVal::Unit; + } + + let charset_name = + FieldName::from_str("charset").unwrap(); + let charset = ty.get_mut(&charset_name).unwrap(); + if let Some(ref charset_params) = + preview_params.mime.charset + { + *charset = + StrictVal::String(charset_params.to_string()); + } else { + *charset = StrictVal::Unit; + } + } + _ => { + panic!("Invalid preview type"); + } + } + + let data_name = FieldName::from_str("data").unwrap(); + let data = s.get_mut(&data_name).unwrap(); + *data = StrictVal::Bytes(Blob(preview_params.data.to_vec())); + } + _ => { + panic!("Invalid preview"); + } + } + + if let Some(ref media_params) = nft_spec.external { + let media_name = FieldName::from_str("media").unwrap(); + let media = s.get_mut(&media_name).unwrap(); + match media { + StrictVal::Struct(s) => { + let media_type_name = FieldName::from_str("type").unwrap(); + let media_type = s.get_mut(&media_type_name).unwrap(); + match media_type { + StrictVal::Struct(ty) => { + let ty_name = FieldName::from_str("type").unwrap(); + let ty_type = ty.get_mut(&ty_name).unwrap(); + *ty_type = StrictVal::String( + media_params.mime.ty.to_string(), + ); + + let subtype_name = + FieldName::from_str("subtype").unwrap(); + let subtype = ty.get_mut(&subtype_name).unwrap(); + if let Some(ref subtype_params) = + media_params.mime.subtype + { + *subtype = StrictVal::String( + subtype_params.to_string(), + ); + } else { + *subtype = StrictVal::Unit; + } + + let charset_name = + FieldName::from_str("charset").unwrap(); + let charset = ty.get_mut(&charset_name).unwrap(); + if let Some(ref charset_params) = + media_params.mime.charset + { + *charset = StrictVal::String( + charset_params.to_string(), + ); + } else { + *charset = StrictVal::Unit; + } + } + _ => { + panic!("Invalid media type"); + } + } + + let data_name = FieldName::from_str("digest").unwrap(); + let data = s.get_mut(&data_name).unwrap(); + *data = + StrictVal::Bytes(Blob(media_params.digest.to_vec())); + } + _ => { + panic!("Invalid media"); + } + } + } + + if let Some(ref reserves_params) = nft_spec.reserves { + let reserves_name = FieldName::from_str("reserves").unwrap(); + let reserves = s.get_mut(&reserves_name).unwrap(); + match reserves { + StrictVal::Struct(s) => { + let utxo_name = FieldName::from_str("utxo").unwrap(); + let utxo = s.get_mut(&utxo_name).unwrap(); + match utxo { + StrictVal::Struct(s) => { + let txid_name = + FieldName::from_str("txid").unwrap(); + let txid = s.get_mut(&txid_name).unwrap(); + *txid = StrictVal::Bytes(Blob( + reserves_params.utxo.txid.to_inner().to_vec(), + )); + + let vout_name = + FieldName::from_str("vout").unwrap(); + let vout = s.get_mut(&vout_name).unwrap(); + *vout = StrictVal::Number(StrictNum::from( + reserves_params.utxo.vout.into_u32(), + )); + } + _ => { + panic!("Invalid utxo"); + } + } + + let proof_name = FieldName::from_str("proof").unwrap(); + let proof = s.get_mut(&proof_name).unwrap(); + *proof = + StrictVal::Bytes(Blob(reserves_params.proof.to_vec())); + } + _ => { + panic!("Invalid reserves"); + } + } + } + } + _ => { + panic!("Invalid NFT spec"); + } + } + } + } + } + + for name_state in create_params.owned.iter_mut() { + let name = VariantName::from_str("fractions").unwrap(); + if name_state.name == name { + let fractions = &mut name_state.state; + fractions.seal = EitherSeal::Alt(params.initial_allocation.as_ref().unwrap().0); + let fractions_data = &mut fractions.data; + + let nft = ¶ms.initial_allocation.as_ref().unwrap().1; + let nft_data = StrictVal::Struct(IndexMap::from([ + ( + FieldName::from_str("tokenIndex").unwrap(), + StrictVal::Number(StrictNum::from(nft.token_no.into_inner())), + ), + ( + FieldName::from_str("fraction").unwrap(), + StrictVal::Number(StrictNum::from(nft.fractions.into_inner())), + ), + ( + FieldName::from_str("align").unwrap(), + StrictVal::Bytes(Blob(vec![0; 26])), + ), + ])); + *fractions_data = nft_data; + } + } + + self.issue_with_params(create_params) + } + + /// Get RGB21 contract state + pub fn contract_state_rgb21(&mut self, contract_id: ContractId) -> Option { + self.contract_state_internal(contract_id) + .map(|(immutable, owned, _)| { + // Parse immutable state + let name = immutable + .get(&VariantName::from_str("name").unwrap()) + .and_then(|m| m.iter().next()) + .map(|v| v.data.verified.unwrap_string()) + .unwrap_or_default(); + + let total_fractions = immutable + .get(&VariantName::from_str("fractions").unwrap()) + .and_then(|m| m.iter().next()) + .map(|v| v.data.verified.unwrap_num().unwrap_uint::()) + .unwrap_or_default(); + + // Parse token/NFT metadata + let token = immutable + .get(&VariantName::from_str("token").unwrap()) + .and_then(|m| m.iter().next()) + .map(|v| { + let mut index = 0u32; + let mut amount = 0u64; + + // Parse verified token data + if let StrictVal::Struct(ref s) = v.data.verified { + if let Some(StrictVal::Number(n)) = + s.get(&FieldName::from_str("index").unwrap()) + { + index = n.unwrap_uint::(); + } + if let Some(StrictVal::Number(n)) = + s.get(&FieldName::from_str("balance").unwrap()) + { + amount = n.unwrap_uint::(); + } + } + + // Parse unverified token metadata + let mut ticker = None; + let mut name = None; + let mut details = None; + let mut preview = None; + let mut media = None; + let mut attachments = BTreeMap::new(); + let mut reserves = None; + + if let Some(ref unverified) = v.data.unverified { + if let StrictVal::Struct(ref s) = unverified { + if let Some(StrictVal::Union(_, t)) = + s.get(&FieldName::from_str("ticker").unwrap()) + { + ticker = + extract_from_2_layer_tuple(t).map(|s| s.unwrap_string()); + } + + if let Some(StrictVal::Union(_, t)) = + s.get(&FieldName::from_str("name").unwrap()) + { + name = extract_from_2_layer_tuple(t).map(|s| s.unwrap_string()); + } + + if let Some(StrictVal::Union(_, t)) = + s.get(&FieldName::from_str("details").unwrap()) + { + details = + extract_from_2_layer_tuple(t).map(|s| s.unwrap_string()); + } + + // Parse preview + let preview_struct = s + .get(&FieldName::from_str("preview").unwrap()) + .and_then(extract_from_union_and_tuple); + + if let Some(StrictVal::Struct(ref p)) = preview_struct { + let media_type = if let Some(StrictVal::Struct(ref t)) = + p.get(&FieldName::from_str("type").unwrap()) + { + let type_value = t + .get(&FieldName::from_str("type").unwrap()) + .and_then(|v| { + extract_from_tuple(v).map(|s| s.unwrap_string()) + }) + .unwrap_or_default(); + + let subtype = t + .get(&FieldName::from_str("subtype").unwrap()) + .and_then(|v| { + extract_from_union_and_2_layer_tuple(v) + .map(|s| s.unwrap_string()) + }); + + let charset = t + .get(&FieldName::from_str("charset").unwrap()) + .and_then(|v| { + extract_from_union_and_2_layer_tuple(v) + .map(|s| s.unwrap_string()) + }); + + MediaTypeData { + r#type: type_value, + subtype, + charset, + } + } else { + MediaTypeData { + r#type: "".to_string(), + subtype: None, + charset: None, + } + }; + + let data = if let Some(StrictVal::Bytes(Blob(d))) = + p.get(&FieldName::from_str("data").unwrap()) + { + d.clone() + } else { + vec![] + }; + + preview = Some(MediaData { media_type, data }); + } + + // Parse media + let media_struct = s + .get(&FieldName::from_str("media").unwrap()) + .and_then(extract_from_union_and_tuple); + + if let Some(StrictVal::Struct(ref m)) = media_struct { + let media_type = if let Some(StrictVal::Struct(ref t)) = + m.get(&FieldName::from_str("type").unwrap()) + { + let type_value = t + .get(&FieldName::from_str("type").unwrap()) + .and_then(|v| { + extract_from_tuple(v).map(|s| s.unwrap_string()) + }) + .unwrap_or_default(); + + let subtype = t + .get(&FieldName::from_str("subtype").unwrap()) + .and_then(|v| { + extract_from_union_and_2_layer_tuple(v) + .map(|s| s.unwrap_string()) + }); + + let charset = t + .get(&FieldName::from_str("charset").unwrap()) + .and_then(|v| { + extract_from_union_and_2_layer_tuple(v) + .map(|s| s.unwrap_string()) + }); + + MediaTypeData { + r#type: type_value, + subtype, + charset, + } + } else { + MediaTypeData { + r#type: "".to_string(), + subtype: None, + charset: None, + } + }; + + let digest = if let Some(StrictVal::Bytes(Blob(d))) = + m.get(&FieldName::from_str("digest").unwrap()) + { + d.clone() + } else { + vec![] + }; + + media = Some(MediaDigest { media_type, digest }); + } + + // Parse attachments + if let Some(StrictVal::Map(ref atts)) = + s.get(&FieldName::from_str("attachments").unwrap()) + { + for (key, value) in atts { + if let ( + StrictVal::Number(idx), + StrictVal::Struct(ref att), + ) = (key, value) + { + let media_type = if let Some(StrictVal::Struct(ref t)) = + att.get(&FieldName::from_str("type").unwrap()) + { + let type_value = t + .get(&FieldName::from_str("type").unwrap()) + .and_then(|v| { + extract_from_tuple(v) + .map(|s| s.unwrap_string()) + }) + .unwrap_or_default(); + + let subtype = t + .get(&FieldName::from_str("subtype").unwrap()) + .and_then(|v| { + extract_from_union_and_2_layer_tuple(v) + .map(|s| s.unwrap_string()) + }); + + let charset = t + .get(&FieldName::from_str("charset").unwrap()) + .and_then(|v| { + extract_from_union_and_2_layer_tuple(v) + .map(|s| s.unwrap_string()) + }); + + MediaTypeData { + r#type: type_value, + subtype, + charset, + } + } else { + MediaTypeData { + r#type: "".to_string(), + subtype: None, + charset: None, + } + }; + + let digest = if let Some(StrictVal::Bytes(Blob(d))) = + att.get(&FieldName::from_str("digest").unwrap()) + { + d.clone() + } else { + vec![] + }; + + let attachment = MediaDigest { media_type, digest }; + + attachments.insert(idx.unwrap_uint::(), attachment); + } + } + } + + // Parse reserves + let reserves_struct = s + .get(&FieldName::from_str("reserves").unwrap()) + .and_then(extract_from_union_and_tuple); + + if let Some(StrictVal::Struct(ref r)) = reserves_struct { + if let Some(StrictVal::Struct(ref u)) = + r.get(&FieldName::from_str("utxo").unwrap()) + { + let txid_bytes = u + .get(&FieldName::from_str("txid").unwrap()) + .and_then(extract_from_tuple) + .and_then(|v| { + if let StrictVal::Bytes(Blob(tx)) = v { + Some(tx) + } else { + None + } + }) + .unwrap_or_default(); + + let vout = u + .get(&FieldName::from_str("vout").unwrap()) + .and_then(extract_from_tuple) + .and_then(|v| { + if let StrictVal::Number(n) = v { + Some(n.unwrap_uint::()) + } else { + None + } + }) + .unwrap_or_default(); + + let txid = if txid_bytes.len() == 32 { + let mut arr = [0u8; 32]; + arr.copy_from_slice(&txid_bytes); + Txid::from_byte_array(arr) + } else { + // default txid + Txid::coinbase() + }; + + let outpoint = Outpoint::new(txid, vout); + + let proof = if let Some(StrictVal::Bytes(Blob(p))) = + r.get(&FieldName::from_str("proof").unwrap()) + { + p.clone() + } else { + vec![] + }; + + reserves = Some(ReserveData { + utxo: outpoint, + proof, + }); + } + } + } + } + + NFTMetadata { + index, + amount, + ticker, + name, + details, + preview, + media, + attachments, + reserves, + } + }); + + // Parse ownership state (fractions) + let mut fractions = vec![]; + if let Some(owned_map) = owned.get(&VariantName::from_str("fractions").unwrap()) { + for state in owned_map { + let amt_val = state.assignment.data.unwrap_num().unwrap_uint::(); + fractions.push((state.assignment.seal, amt_val)); + } + } + + RGB21ContractState { + immutable: RGB21ContractImmutableState { + name, + total_fractions, + token, + }, + owned: RGB21ContractOwnedState { fractions }, + } + }) + } +} diff --git a/tests/utils/helpers.rs b/tests/utils/helpers.rs deleted file mode 100644 index f949a1c..0000000 --- a/tests/utils/helpers.rs +++ /dev/null @@ -1,1713 +0,0 @@ -use super::*; - -pub struct TestWallet { - wallet: RgbWallet>, - descriptor: RgbDescr, - signer: Option, - wallet_dir: PathBuf, - instance: u8, -} - -enum WalletAccount { - Private(XprivAccount), - Public(XpubAccount), -} - -pub enum AllocationFilter { - Stock, - Wallet, - WalletAll, - WalletTentative, -} - -enum Filter<'w> { - NoWallet, - Wallet(&'w RgbWallet>), - WalletAll(&'w RgbWallet>), - WalletTentative(&'w RgbWallet>), -} - -impl AssignmentsFilter for Filter<'_> { - fn should_include(&self, outpoint: impl Into, id: Option) -> bool { - match self { - Filter::Wallet(wallet) => wallet - .wallet() - .filter_unspent() - .should_include(outpoint, id), - Filter::WalletTentative(wallet) => wallet - .wallet() - .filter_outpoints() - .should_include(outpoint, id), - _ => true, - } - } -} -impl Filter<'_> { - fn comment(&self, outpoint: XOutpoint) -> &'static str { - let outpoint = outpoint - .into_bp() - .into_bitcoin() - .expect("liquid is not yet supported"); - match self { - Filter::Wallet(rgb) if rgb.wallet().is_unspent(outpoint) => "", - Filter::WalletAll(rgb) | Filter::WalletTentative(rgb) - if rgb.wallet().is_unspent(outpoint) => - { - "-- unspent" - } - Filter::WalletAll(rgb) | Filter::WalletTentative(rgb) - if rgb.wallet().has_outpoint(outpoint) => - { - "-- spent" - } - _ => "-- third-party", - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum DescriptorType { - Wpkh, - Tr, -} - -impl fmt::Display for DescriptorType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", format!("{:?}", self).to_lowercase()) - } -} - -#[derive(Debug, Copy, Clone)] -pub enum HistoryType { - Linear, - Branching, - Merging, -} - -#[derive(Debug, Copy, Clone)] -pub enum ReorgType { - ChangeOrder, - Revert, -} - -#[derive(Debug, Copy, Clone)] -pub enum TransferType { - Blinded, - Witness, -} - -impl fmt::Display for TransferType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", format!("{:?}", self).to_lowercase()) - } -} - -pub enum InvoiceType { - Blinded(Option), - Witness, -} - -impl From for InvoiceType { - fn from(transfer_type: TransferType) -> Self { - match transfer_type { - TransferType::Blinded => InvoiceType::Blinded(None), - TransferType::Witness => InvoiceType::Witness, - } - } -} - -/// RGB asset-specific information to color a transaction -#[derive(Clone, Debug)] -pub struct AssetColoringInfo { - /// Contract iface - pub iface: TypeName, - /// Input outpoints of the assets being spent - pub input_outpoints: Vec, - /// Map of vouts and asset amounts to color the transaction outputs - pub output_map: HashMap, - /// Static blinding to keep the transaction construction deterministic - pub static_blinding: Option, -} - -/// RGB information to color a transaction -#[derive(Clone, Debug)] -pub struct ColoringInfo { - /// Asset-specific information - pub asset_info_map: HashMap, - /// Static blinding to keep the transaction construction deterministic - pub static_blinding: Option, - /// Nonce for offchain TXs ordering - pub nonce: Option, -} - -/// Map of contract ID and list of its beneficiaries -pub type AssetBeneficiariesMap = BTreeMap>>; - -#[derive(Debug, EnumIter, Copy, Clone, PartialEq)] -pub enum AssetSchema { - Nia, - Uda, - Cfa, -} - -impl fmt::Display for AssetSchema { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", format!("{:?}", self).to_lowercase()) - } -} - -impl AssetSchema { - fn iface_type_name(&self) -> TypeName { - tn!(match self { - Self::Nia => "RGB20Fixed", - Self::Uda => "RGB21Unique", - Self::Cfa => "RGB25Base", - }) - } - - fn schema(&self) -> Schema { - match self { - Self::Nia => NonInflatableAsset::schema(), - Self::Uda => UniqueDigitalAsset::schema(), - Self::Cfa => CollectibleFungibleAsset::schema(), - } - } - - fn issue_impl(&self) -> IfaceImpl { - match self { - Self::Nia => NonInflatableAsset::issue_impl(), - Self::Uda => UniqueDigitalAsset::issue_impl(), - Self::Cfa => CollectibleFungibleAsset::issue_impl(), - } - } - - fn scripts(&self) -> Scripts { - match self { - Self::Nia => NonInflatableAsset::scripts(), - Self::Uda => UniqueDigitalAsset::scripts(), - Self::Cfa => CollectibleFungibleAsset::scripts(), - } - } - - fn types(&self) -> TypeSystem { - match self { - Self::Nia => NonInflatableAsset::types(), - Self::Uda => UniqueDigitalAsset::types(), - Self::Cfa => CollectibleFungibleAsset::types(), - } - } - - fn iface(&self) -> Iface { - match self { - Self::Nia => Rgb20::iface(&Rgb20::FIXED), - Self::Uda => Rgb21::iface(&Rgb21::NONE), - Self::Cfa => Rgb25::iface(&Rgb25::NONE), - } - } - - fn get_valid_kit(&self) -> ValidKit { - let mut kit = Kit::default(); - kit.schemata.push(self.schema()).unwrap(); - kit.ifaces.push(self.iface()).unwrap(); - kit.iimpls.push(self.issue_impl()).unwrap(); - kit.scripts.extend(self.scripts().into_values()).unwrap(); - kit.types = self.types(); - kit.validate().unwrap() - } -} - -#[derive(Debug)] -pub enum AssetInfo { - Nia { - spec: AssetSpec, - terms: ContractTerms, - issue_amounts: Vec, - }, - Uda { - spec: AssetSpec, - terms: ContractTerms, - token_data: TokenData, - }, - Cfa { - name: Name, - precision: Precision, - details: Option
, - terms: ContractTerms, - issue_amounts: Vec, - }, -} - -impl AssetInfo { - fn asset_schema(&self) -> AssetSchema { - match self { - Self::Nia { .. } => AssetSchema::Nia, - Self::Uda { .. } => AssetSchema::Uda, - Self::Cfa { .. } => AssetSchema::Cfa, - } - } - - fn iface_type_name(&self) -> TypeName { - self.asset_schema().iface_type_name() - } - - fn schema(&self) -> Schema { - self.asset_schema().schema() - } - - fn issue_impl(&self) -> IfaceImpl { - self.asset_schema().issue_impl() - } - - fn scripts(&self) -> Scripts { - self.asset_schema().scripts() - } - - fn types(&self) -> TypeSystem { - self.asset_schema().types() - } - - fn iface(&self) -> Iface { - self.asset_schema().iface() - } - - pub fn default_cfa(issue_amounts: Vec) -> Self { - AssetInfo::cfa("CFA asset name", 0, None, "CFA terms", None, issue_amounts) - } - - pub fn default_nia(issue_amounts: Vec) -> Self { - AssetInfo::nia( - "NIATCKR", - "NIA asset name", - 2, - None, - "NIA terms", - None, - issue_amounts, - ) - } - - pub fn default_uda() -> Self { - AssetInfo::uda( - "UDATCKR", - "UDA asset name", - None, - "NIA terms", - None, - uda_token_data_minimal(), - ) - } - - pub fn nia( - ticker: &str, - name: &str, - precision: u8, - details: Option<&str>, - terms_text: &str, - terms_media_fpath: Option<&str>, - issue_amounts: Vec, - ) -> Self { - let spec = AssetSpec::with( - ticker, - name, - Precision::try_from(precision).unwrap(), - details, - ) - .unwrap(); - let text = RicardianContract::from_str(terms_text).unwrap(); - let attachment = terms_media_fpath.map(attachment_from_fpath); - let terms = ContractTerms { - text, - media: attachment, - }; - Self::Nia { - spec, - terms, - issue_amounts, - } - } - - pub fn uda( - ticker: &str, - name: &str, - details: Option<&str>, - terms_text: &str, - terms_media_fpath: Option<&str>, - token_data: TokenData, - ) -> AssetInfo { - let spec = AssetSpec::with(ticker, name, Precision::try_from(0).unwrap(), details).unwrap(); - let text = RicardianContract::from_str(terms_text).unwrap(); - let attachment = terms_media_fpath.map(attachment_from_fpath); - let terms = ContractTerms { - text, - media: attachment.clone(), - }; - Self::Uda { - spec, - terms, - token_data, - } - } - - pub fn cfa( - name: &str, - precision: u8, - details: Option<&str>, - terms_text: &str, - terms_media_fpath: Option<&str>, - issue_amounts: Vec, - ) -> AssetInfo { - let text = RicardianContract::from_str(terms_text).unwrap(); - let attachment = terms_media_fpath.map(attachment_from_fpath); - let terms = ContractTerms { - text, - media: attachment, - }; - Self::Cfa { - name: Name::try_from(name.to_owned()).unwrap(), - precision: Precision::try_from(precision).unwrap(), - details: details.map(|d| Details::try_from(d.to_owned()).unwrap()), - terms, - issue_amounts, - } - } - - fn add_global_state(&self, mut builder: ContractBuilder) -> ContractBuilder { - match self { - Self::Nia { - spec, - terms, - issue_amounts, - } => builder - .add_global_state("spec", spec.clone()) - .unwrap() - .add_global_state("terms", terms.clone()) - .unwrap() - .add_global_state( - "issuedSupply", - Amount::from(issue_amounts.iter().sum::()), - ) - .unwrap(), - Self::Uda { - spec, - terms, - token_data, - } => builder - .add_global_state("spec", spec.clone()) - .unwrap() - .add_global_state("terms", terms.clone()) - .unwrap() - .add_global_state("tokens", token_data.clone()) - .unwrap(), - Self::Cfa { - name, - precision, - details, - terms, - issue_amounts: issued_supply, - } => { - builder = builder - .add_global_state("name", name.clone()) - .unwrap() - .add_global_state("precision", *precision) - .unwrap() - .add_global_state("terms", terms.clone()) - .unwrap() - .add_global_state( - "issuedSupply", - Amount::from(issued_supply.iter().sum::()), - ) - .unwrap(); - if let Some(details) = details { - builder = builder - .add_global_state("details", details.clone()) - .unwrap() - } - builder - } - } - } - - fn add_asset_owner( - &self, - mut builder: ContractBuilder, - close_method: CloseMethod, - outpoints: Vec, - ) -> ContractBuilder { - fn get_genesis_seal( - close_method: CloseMethod, - outpoint: Outpoint, - ) -> BuilderSeal> { - let blind_seal = match close_method { - CloseMethod::TapretFirst => { - BlindSeal::tapret_first_rand(outpoint.txid, outpoint.vout) - } - CloseMethod::OpretFirst => { - BlindSeal::opret_first_rand(outpoint.txid, outpoint.vout) - } - }; - let genesis_seal = GenesisSeal::from(blind_seal); - let seal: XChain> = XChain::with(Layer1::Bitcoin, genesis_seal); - BuilderSeal::from(seal) - } - - match self { - Self::Nia { issue_amounts, .. } | Self::Cfa { issue_amounts, .. } => { - for (amt, outpoint) in issue_amounts.iter().zip(outpoints.iter().cycle()) { - builder = builder - .add_fungible_state( - "assetOwner", - get_genesis_seal(close_method, *outpoint), - *amt, - ) - .unwrap(); - } - builder - } - Self::Uda { token_data, .. } => { - let fraction = OwnedFraction::from(1); - let allocation = Allocation::with(token_data.index, fraction); - builder - .add_data( - "assetOwner", - get_genesis_seal(close_method, outpoints[0]), - allocation, - ) - .unwrap() - } - } - } -} - -pub struct Report { - pub report_path: PathBuf, -} - -impl Report { - pub fn write_header(&self, fields: &[&str]) { - let mut file = std::fs::File::options() - .read(true) - .write(true) - .create_new(true) - .open(&self.report_path) - .unwrap(); - file.write_all(format!("{}\n", fields.join(";")).as_bytes()) - .unwrap(); - } - - pub fn write_duration(&self, duration: Duration) { - let mut file = OpenOptions::new() - .append(true) - .open(&self.report_path) - .unwrap(); - file.write_all(format!("{};", duration.as_millis()).as_bytes()) - .unwrap(); - } - - pub fn end_line(&self) { - let mut file = OpenOptions::new() - .append(true) - .open(&self.report_path) - .unwrap(); - file.write_all("\n".as_bytes()).unwrap(); - } -} - -fn _get_wallet( - descriptor_type: &DescriptorType, - network: Network, - wallet_dir: PathBuf, - wallet_account: WalletAccount, - instance: u8, -) -> TestWallet { - std::fs::create_dir_all(&wallet_dir).unwrap(); - println!("wallet dir: {wallet_dir:?}"); - - let xpub_account = match wallet_account { - WalletAccount::Private(ref xpriv_account) => xpriv_account.to_xpub_account(), - WalletAccount::Public(ref xpub_account) => xpub_account.clone(), - }; - const OPRET_KEYCHAINS: [Keychain; 3] = [ - Keychain::INNER, - Keychain::OUTER, - Keychain::with(RgbKeychain::Rgb as u8), - ]; - const TAPRET_KEYCHAINS: [Keychain; 4] = [ - Keychain::INNER, - Keychain::OUTER, - Keychain::with(RgbKeychain::Rgb as u8), - Keychain::with(RgbKeychain::Tapret as u8), - ]; - let keychains: &[Keychain] = match *descriptor_type { - DescriptorType::Tr => &TAPRET_KEYCHAINS[..], - DescriptorType::Wpkh => &OPRET_KEYCHAINS[..], - }; - let xpub_derivable = XpubDerivable::with(xpub_account.clone(), keychains); - - let descriptor = match descriptor_type { - DescriptorType::Wpkh => RgbDescr::Wpkh(Wpkh::from(xpub_derivable)), - DescriptorType::Tr => RgbDescr::TapretKey(TapretKey::from(xpub_derivable)), - }; - - let name = "bp_wallet_name"; - let mut bp_wallet = Wallet::new_layer1(descriptor.clone(), network); - bp_wallet.set_name(name.to_string()); - let bp_dir = wallet_dir.join(name); - let bp_wallet_provider = FsTextStore::new(bp_dir).unwrap(); - bp_wallet.make_persistent(bp_wallet_provider, true).unwrap(); - - let stock_provider = FsBinStore::new(wallet_dir.clone()).unwrap(); - let mut stock = Stock::in_memory(); - stock.make_persistent(stock_provider, true).unwrap(); - let mut wallet = RgbWallet::new(stock, bp_wallet); - - for asset_schema in AssetSchema::iter() { - let valid_kit = asset_schema.get_valid_kit(); - wallet.stock_mut().import_kit(valid_kit).unwrap(); - } - - let signer = match wallet_account { - WalletAccount::Private(xpriv_account) => Some(TestnetSigner::new(xpriv_account)), - WalletAccount::Public(_) => None, - }; - - let mut wallet = TestWallet { - wallet, - descriptor, - signer, - wallet_dir, - instance, - }; - - // TODO: remove if once found solution for esplora 'Too many requests' error - if network.is_testnet() { - wallet.sync(); - } - - wallet -} - -pub fn get_wallet(descriptor_type: &DescriptorType) -> TestWallet { - get_wallet_custom(descriptor_type, INSTANCE_1) -} - -pub fn get_wallet_custom(descriptor_type: &DescriptorType, instance: u8) -> TestWallet { - let mut seed = vec![0u8; 128]; - rand::thread_rng().fill_bytes(&mut seed); - - let xpriv_account = XprivAccount::with_seed(true, &seed).derive(h![86, 1, 0]); - - let fingerprint = xpriv_account.account_fp().to_string(); - let wallet_dir = PathBuf::from(TEST_DATA_DIR) - .join(INTEGRATION_DATA_DIR) - .join(fingerprint); - - _get_wallet( - descriptor_type, - Network::Regtest, - wallet_dir, - WalletAccount::Private(xpriv_account), - instance, - ) -} - -pub fn get_mainnet_wallet() -> TestWallet { - let xpub_account = XpubAccount::from_str( - "[c32338a7/86h/0h/0h]xpub6CmiK1xc7YwL472qm4zxeURFX8yMCSasioXujBjVMMzA3AKZr6KLQEmkzDge1Ezn2p43ZUysyx6gfajFVVnhtQ1AwbXEHrioLioXXgj2xW5" - ).unwrap(); - - let wallet_dir = PathBuf::from(TEST_DATA_DIR) - .join(INTEGRATION_DATA_DIR) - .join("mainnet"); - - _get_wallet( - &DescriptorType::Wpkh, - Network::Mainnet, - wallet_dir, - WalletAccount::Public(xpub_account), - INSTANCE_1, - ) -} - -fn get_indexer(indexer_url: &str) -> AnyIndexer { - match INDEXER.get().unwrap() { - Indexer::Electrum => { - AnyIndexer::Electrum(Box::new(ElectrumClient::new(indexer_url).unwrap())) - } - Indexer::Esplora => { - AnyIndexer::Esplora(Box::new(EsploraClient::new_esplora(indexer_url).unwrap())) - } - } -} - -fn get_resolver(indexer_url: &str) -> AnyResolver { - match INDEXER.get().unwrap() { - Indexer::Electrum => AnyResolver::electrum_blocking(indexer_url, None).unwrap(), - Indexer::Esplora => AnyResolver::esplora_blocking(indexer_url, None).unwrap(), - } -} - -fn broadcast_tx(tx: &Tx, indexer_url: &str) { - match get_indexer(indexer_url) { - AnyIndexer::Electrum(inner) => { - inner.transaction_broadcast(tx).unwrap(); - } - AnyIndexer::Esplora(inner) => { - inner.publish(tx).unwrap(); - } - _ => unreachable!("unsupported indexer"), - } -} - -pub fn broadcast_tx_and_mine(tx: &Tx, instance: u8) { - broadcast_tx(tx, &indexer_url(instance, Network::Regtest)); - mine_custom(false, instance, 1); -} - -pub fn attachment_from_fpath(fpath: &str) -> Attachment { - let file_bytes = std::fs::read(fpath).unwrap(); - let file_hash: sha256::Hash = Hash::hash(&file_bytes[..]); - let digest = file_hash.to_byte_array().into(); - let mime = FileFormat::from_file(fpath) - .unwrap() - .media_type() - .to_string(); - let media_ty: &'static str = Box::leak(mime.clone().into_boxed_str()); - let media_type = MediaType::with(media_ty); - Attachment { - ty: media_type, - digest, - } -} - -fn uda_token_data_minimal() -> TokenData { - TokenData { - index: TokenIndex::from(UDA_FIXED_INDEX), - ..Default::default() - } -} - -pub fn uda_token_data( - ticker: &str, - name: &str, - details: &str, - preview: EmbeddedMedia, - media: Attachment, - attachments: BTreeMap, - reserves: ProofOfReserves, -) -> TokenData { - let mut token_data = uda_token_data_minimal(); - token_data.preview = Some(preview); - token_data.media = Some(media); - token_data.attachments = Confined::try_from(attachments.clone()).unwrap(); - token_data.reserves = Some(reserves); - token_data.ticker = Some(Ticker::try_from(ticker.to_string()).unwrap()); - token_data.name = Some(Name::try_from(name.to_string()).unwrap()); - token_data.details = Some(Details::try_from(details.to_string()).unwrap()); - token_data -} - -impl TestWallet { - pub fn network(&self) -> Network { - self.wallet.wallet().network() - } - - pub fn testnet(&self) -> bool { - self.network().is_testnet() - } - - pub fn keychain(&self) -> RgbKeychain { - RgbKeychain::for_method(self.close_method()) - } - - pub fn get_derived_address(&self) -> DerivedAddr { - self.wallet - .wallet() - .addresses(self.keychain()) - .next() - .expect("no addresses left") - } - - pub fn get_address(&self) -> Address { - self.get_derived_address().addr - } - - pub fn get_utxo(&mut self, sats: Option) -> Outpoint { - let address = self.get_address(); - let txid = Txid::from_str(&fund_wallet(address.to_string(), sats, self.instance)).unwrap(); - self.sync(); - let mut vout = None; - let coins = self.wallet.wallet().address_coins(); - assert!(!coins.is_empty()); - for (_derived_addr, utxos) in coins { - for utxo in utxos { - if utxo.outpoint.txid == txid { - vout = Some(utxo.outpoint.vout_u32()); - } - } - } - Outpoint { - txid, - vout: Vout::from_u32(vout.unwrap()), - } - } - - pub fn change_instance(&mut self, instance: u8) { - self.instance = instance; - } - - pub fn sync_and_update_witnesses(&mut self, after_height: Option) { - self.sync(); - self.update_witnesses(after_height.unwrap_or(1)); - } - - pub fn switch_to_instance(&mut self, instance: u8) { - self.change_instance(instance); - self.sync_and_update_witnesses(None); - } - - pub fn indexer_url(&self) -> String { - indexer_url(self.instance, self.network()) - } - - fn get_indexer(&self) -> AnyIndexer { - get_indexer(&self.indexer_url()) - } - - pub fn get_resolver(&self) -> AnyResolver { - get_resolver(&self.indexer_url()) - } - - pub fn broadcast_tx(&self, tx: &Tx) { - broadcast_tx(tx, &self.indexer_url()); - } - - pub fn get_witness_ord(&self, txid: &Txid) -> WitnessOrd { - self.get_resolver() - .resolve_pub_witness_ord(XWitnessId::Bitcoin(*txid)) - .unwrap() - } - - pub fn get_tx_height(&self, txid: &Txid) -> Option { - match self.get_witness_ord(txid) { - WitnessOrd::Mined(witness_pos) => Some(witness_pos.height().get()), - _ => None, - } - } - - pub fn sync(&mut self) { - let indexer = self.get_indexer(); - self.wallet - .wallet_mut() - .update(&indexer) - .into_result() - .unwrap(); - } - - pub fn close_method(&self) -> CloseMethod { - self.wallet.wallet().seal_close_method() - } - - pub fn mine_tx(&self, txid: &Txid, resume: bool) { - let mut attempts = 10; - loop { - mine_custom(resume, self.instance, 1); - if self.get_tx_height(txid).is_some() { - break; - } - attempts -= 1; - if attempts == 0 { - panic!("TX is not getting mined"); - } - } - } - - pub fn issue_with_info( - &mut self, - asset_info: AssetInfo, - close_method: CloseMethod, - outpoints: Vec>, - ) -> (ContractId, TypeName) { - let outpoints = if outpoints.is_empty() { - vec![self.get_utxo(None)] - } else { - outpoints - .into_iter() - .map(|o| o.unwrap_or_else(|| self.get_utxo(None))) - .collect() - }; - - let mut builder = ContractBuilder::with( - Identity::default(), - asset_info.iface(), - asset_info.schema(), - asset_info.issue_impl(), - asset_info.types(), - asset_info.scripts(), - ); - - builder = asset_info.add_global_state(builder); - - builder = asset_info.add_asset_owner(builder, close_method, outpoints); - - let contract = builder.issue_contract().expect("failure issuing contract"); - let resolver = self.get_resolver(); - self.wallet - .stock_mut() - .import_contract(contract.clone(), resolver) - .unwrap(); - - (contract.contract_id(), asset_info.iface_type_name()) - } - - pub fn issue_nia( - &mut self, - issued_supply: u64, - close_method: CloseMethod, - outpoint: Option<&Outpoint>, - ) -> (ContractId, TypeName) { - let asset_info = AssetInfo::default_nia(vec![issued_supply]); - self.issue_with_info(asset_info, close_method, vec![outpoint.copied()]) - } - - pub fn issue_uda( - &mut self, - close_method: CloseMethod, - outpoint: Option<&Outpoint>, - ) -> (ContractId, TypeName) { - let asset_info = AssetInfo::default_uda(); - self.issue_with_info(asset_info, close_method, vec![outpoint.copied()]) - } - - pub fn issue_cfa( - &mut self, - issued_supply: u64, - close_method: CloseMethod, - outpoint: Option<&Outpoint>, - ) -> (ContractId, TypeName) { - let asset_info = AssetInfo::default_cfa(vec![issued_supply]); - self.issue_with_info(asset_info, close_method, vec![outpoint.copied()]) - } - - pub fn invoice( - &mut self, - contract_id: ContractId, - iface_type_name: &TypeName, - amount: u64, - close_method: CloseMethod, - invoice_type: InvoiceType, - ) -> RgbInvoice { - let network = self.wallet.wallet().network(); - let beneficiary = match invoice_type { - InvoiceType::Blinded(outpoint) => { - let outpoint = if let Some(outpoint) = outpoint { - outpoint - } else { - self.get_utxo(None) - }; - let seal = XChain::Bitcoin(GraphSeal::new_random( - close_method, - outpoint.txid, - outpoint.vout, - )); - self.wallet.stock_mut().store_secret_seal(seal).unwrap(); - Beneficiary::BlindedSeal(*seal.to_secret_seal().as_reduced_unsafe()) - } - InvoiceType::Witness => { - let address = self.get_address(); - Beneficiary::WitnessVout(Pay2Vout { - address: address.payload, - method: close_method, - }) - } - }; - - let mut builder = RgbInvoiceBuilder::new(XChainNet::bitcoin(network, beneficiary)) - .set_contract(contract_id) - .set_interface(iface_type_name.clone()); - if *iface_type_name == AssetSchema::Uda.iface_type_name() { - if amount != 1 { - panic!("UDA amount must be 1"); - } - builder = builder - .clone() - .set_allocation(UDA_FIXED_INDEX, amount) - .unwrap(); - } else { - builder = builder.clone().set_amount_raw(amount); - } - builder.finish() - } - - pub fn sign_finalize(&self, psbt: &mut Psbt) { - let _sig_count = psbt.sign(self.signer.as_ref().unwrap()).unwrap(); - psbt.finalize(&self.descriptor); - } - - pub fn sign_finalize_extract(&self, psbt: &mut Psbt) -> Tx { - self.sign_finalize(psbt); - psbt.extract().unwrap() - } - - pub fn transfer( - &mut self, - invoice: RgbInvoice, - sats: Option, - fee: Option, - broadcast: bool, - report: Option<&Report>, - ) -> (Transfer, Tx) { - self.sync(); - - let fee = Sats::from_sats(fee.unwrap_or(DEFAULT_FEE_ABS)); - let sats = Sats::from_sats(sats.unwrap_or(2000)); - let params = TransferParams::with(fee, sats); - let pay_start = Instant::now(); - let (mut psbt, _psbt_meta, consignment) = self.wallet.pay(&invoice, params).unwrap(); - let pay_duration = pay_start.elapsed(); - if let Some(report) = report { - report.write_duration(pay_duration); - } - - let mut cs_path = self.wallet_dir.join("consignments"); - std::fs::create_dir_all(&cs_path).unwrap(); - let consignment_id = consignment.consignment_id(); - cs_path.push(consignment_id.to_string()); - cs_path.set_extension("yaml"); - let mut file = std::fs::File::options() - .read(true) - .write(true) - .create_new(true) - .open(cs_path) - .unwrap(); - serde_yaml::to_writer(&mut file, &consignment).unwrap(); - - let tx = self.sign_finalize_extract(&mut psbt); - - let txid = tx.txid().to_string(); - println!("transfer txid: {txid}, consignment: {consignment_id}"); - - let mut tx_path = self.wallet_dir.join("transactions"); - std::fs::create_dir_all(&tx_path).unwrap(); - tx_path.push(&txid); - tx_path.set_extension("yaml"); - let mut file = std::fs::File::options() - .read(true) - .write(true) - .create_new(true) - .open(tx_path) - .unwrap(); - serde_yaml::to_writer(&mut file, &tx).unwrap(); - writeln!(file, "\n---\n").unwrap(); - serde_yaml::to_writer(&mut file, &psbt).unwrap(); - - if broadcast { - self.broadcast_tx(&tx); - } - - (consignment, tx) - } - - pub fn accept_transfer(&mut self, consignment: Transfer, report: Option<&Report>) { - let mut resolver = self.get_resolver(); - resolver.add_terminals(&consignment); - self.accept_transfer_custom_resolver(consignment, report, &resolver); - } - - pub fn accept_transfer_custom_resolver( - &mut self, - consignment: Transfer, - report: Option<&Report>, - resolver: &impl ResolveWitness, - ) { - self.sync(); - let validate_start = Instant::now(); - let validated_consignment = consignment - .validate(&resolver, self.testnet()) - .map_err(|(status, _)| status) - .unwrap(); - let validate_duration = validate_start.elapsed(); - if let Some(report) = report { - report.write_duration(validate_duration); - } - - let validation_status = validated_consignment.clone().into_validation_status(); - let validity = validation_status.validity(); - assert_eq!(validity, Validity::Valid); - let accept_start = Instant::now(); - self.wallet - .stock_mut() - .accept_transfer(validated_consignment.clone(), &resolver) - .unwrap(); - let accept_duration = accept_start.elapsed(); - if let Some(report) = report { - report.write_duration(accept_duration); - } - } - - pub fn contract_iface( - &self, - contract_id: ContractId, - iface_type_name: &TypeName, - ) -> ContractIface> { - self.wallet - .stock() - .contract_iface(contract_id, iface_type_name.clone()) - .unwrap() - } - - pub fn contract_iface_class( - &self, - contract_id: ContractId, - ) -> C::Wrapper> { - self.wallet - .stock() - .contract_iface_class::(contract_id) - .unwrap() - } - - pub fn contract_fungible_allocations( - &self, - contract_id: ContractId, - iface_type_name: &TypeName, - show_tentative: bool, - ) -> Vec { - let filter = if show_tentative { - Filter::WalletTentative(&self.wallet) - } else { - Filter::Wallet(&self.wallet) - }; - self.contract_iface(contract_id, iface_type_name) - .fungible(fname!("assetOwner"), filter) - .unwrap() - .collect() - } - - pub fn contract_data_allocations( - &self, - contract_id: ContractId, - iface_type_name: &TypeName, - ) -> Vec { - self.contract_iface(contract_id, iface_type_name) - .data(fname!("assetOwner"), Filter::Wallet(&self.wallet)) - .unwrap() - .collect() - } - - pub fn history(&self, contract_id: ContractId, iface_type_name: &TypeName) -> Vec { - self.wallet - .history(contract_id, iface_type_name.clone()) - .unwrap() - } - - pub fn list_contracts(&self) -> Vec { - self.wallet.stock().contracts().unwrap().collect() - } - - pub fn debug_contracts(&self) { - println!("Contracts:"); - for info in self.list_contracts() { - println!("{}", info.to_string().replace("\n", "\t")); - } - } - - pub fn debug_logs( - &self, - contract_id: ContractId, - iface_type_name: &TypeName, - filter: AllocationFilter, - ) { - let filter = match filter { - AllocationFilter::WalletAll => Filter::WalletAll(&self.wallet), - AllocationFilter::WalletTentative => Filter::WalletTentative(&self.wallet), - AllocationFilter::Wallet => Filter::Wallet(&self.wallet), - AllocationFilter::Stock => Filter::NoWallet, - }; - - let contract = self.contract_iface(contract_id, iface_type_name); - - println!("Global:"); - for global in &contract.iface.global_state { - if let Ok(values) = contract.global(global.name.clone()) { - for val in values { - println!(" {} := {}", global.name, val); - } - } - } - - println!("\nOwned:"); - fn witness( - allocation: &OutputAssignment, - contract: &ContractIface>, - ) -> String { - allocation - .witness - .and_then(|w| contract.witness_info(w)) - .map(|info| format!("{} ({})", info.id, info.ord)) - .unwrap_or_else(|| s!("~")) - } - for owned in &contract.iface.assignments { - println!(" State \t{:78}\tWitness", "Seal"); - println!(" {}:", owned.name); - if let Ok(allocations) = contract.fungible(owned.name.clone(), &filter) { - for allocation in allocations { - println!( - " {: >9}\t{}\t{} {}", - allocation.state.value(), - allocation.seal, - witness(&allocation, &contract), - filter.comment(allocation.seal.to_outpoint()) - ); - } - } - if let Ok(allocations) = contract.data(owned.name.clone(), &filter) { - for allocation in allocations { - println!( - " {: >9}\t{}\t{} {}", - allocation.state, - allocation.seal, - witness(&allocation, &contract), - filter.comment(allocation.seal.to_outpoint()) - ); - } - } - if let Ok(allocations) = contract.attachments(owned.name.clone(), &filter) { - for allocation in allocations { - println!( - " {: >9}\t{}\t{} {}", - allocation.state, - allocation.seal, - witness(&allocation, &contract), - filter.comment(allocation.seal.to_outpoint()) - ); - } - } - if let Ok(allocations) = contract.rights(owned.name.clone(), &filter) { - for allocation in allocations { - println!( - " {: >9}\t{}\t{} {}", - "right", - allocation.seal, - witness(&allocation, &contract), - filter.comment(allocation.seal.to_outpoint()) - ); - } - } - } - - let bp_runtime = self.wallet.wallet(); - println!("\nHeight\t{:>12}\t{:68}", "Amount, ṩ", "Outpoint"); - for (derived_addr, utxos) in bp_runtime.address_coins() { - println!("{}\t{}", derived_addr.addr, derived_addr.terminal); - for row in utxos { - println!("{}\t{: >12}\t{:68}", row.height, row.amount, row.outpoint); - } - println!() - } - - println!("\nWallet total balance: {} ṩ", bp_runtime.balance()); - } - - pub fn debug_history( - &self, - contract_id: ContractId, - iface_type_name: &TypeName, - details: bool, - ) { - let mut history = self.history(contract_id, iface_type_name); - history.sort_by_key(|op| op.witness.map(|w| w.ord).unwrap_or(WitnessOrd::Archived)); - if details { - println!("Operation\tValue \tState\t{:78}\tWitness", "Seal"); - } else { - println!("Operation\tValue \t{:78}\tWitness", "Seal"); - } - for ContractOp { - direction, - ty, - opids, - state, - to, - witness, - } in history - { - print!("{:9}\t", direction.to_string()); - if let AllocatedState::Amount(amount) = state { - print!("{: >9}", amount.value()); - } else { - print!("{state:>9}"); - } - if details { - print!("\t{ty}"); - } - println!( - "\t{}\t{}", - to.first().expect("at least one receiver is always present"), - witness - .map(|info| format!("{} ({})", info.id, info.ord)) - .unwrap_or_else(|| s!("~")) - ); - if details { - println!( - "\topid={}", - opids - .iter() - .map(OpId::to_string) - .collect::>() - .join("\n\topid=") - ) - } - } - } - - #[allow(clippy::too_many_arguments)] - pub fn send( - &mut self, - recv_wlt: &mut TestWallet, - transfer_type: TransferType, - contract_id: ContractId, - iface_type_name: &TypeName, - amount: u64, - sats: u64, - report: Option<&Report>, - ) -> (Transfer, Tx) { - let invoice = recv_wlt.invoice( - contract_id, - iface_type_name, - amount, - recv_wlt.close_method(), - transfer_type.into(), - ); - self.send_to_invoice(recv_wlt, invoice, Some(sats), None, report) - } - - pub fn send_to_invoice( - &mut self, - recv_wlt: &mut TestWallet, - invoice: RgbInvoice, - sats: Option, - fee: Option, - report: Option<&Report>, - ) -> (Transfer, Tx) { - let (consignment, tx) = self.transfer(invoice, sats, fee, true, report); - self.mine_tx(&tx.txid(), false); - recv_wlt.accept_transfer(consignment.clone(), report); - self.sync(); - (consignment, tx) - } - - pub fn check_allocations( - &self, - contract_id: ContractId, - iface_type_name: &TypeName, - asset_schema: AssetSchema, - expected_fungible_allocations: Vec, - nonfungible_allocation: bool, - ) { - match asset_schema { - AssetSchema::Nia | AssetSchema::Cfa => { - let allocations = - self.contract_fungible_allocations(contract_id, iface_type_name, false); - let mut actual_fungible_allocations = allocations - .iter() - .map(|a| a.state.value()) - .collect::>(); - let mut expected_fungible_allocations = expected_fungible_allocations.clone(); - actual_fungible_allocations.sort(); - expected_fungible_allocations.sort(); - assert_eq!(actual_fungible_allocations, expected_fungible_allocations); - assert!(allocations - .iter() - .all(|a| a.seal.method() == self.close_method())); - } - AssetSchema::Uda => { - let allocations = self.contract_data_allocations(contract_id, iface_type_name); - let expected_allocations = if nonfungible_allocation { - assert_eq!( - allocations - .iter() - .filter(|a| a.state.to_string() == "000000000100000000000000") - .count(), - 1 - ); - 1 - } else { - 0 - }; - assert_eq!(allocations.len(), expected_allocations); - } - } - } - - pub fn check_history_operation( - &self, - contract_id: &ContractId, - iface_type_name: &TypeName, - txid: Option<&Txid>, - direction: OpDirection, - amount: u64, - ) { - let operation = self - .history(*contract_id, iface_type_name) - .into_iter() - .find(|co| { - co.direction == direction - && co - .witness - .map_or(true, |w| Some(w.id.as_reduced_unsafe()) == txid) - }) - .unwrap(); - assert!(matches!(operation.state, AllocatedState::Amount(amt) if amt.value() == amount)); - } - - fn _construct_psbt_offchain( - &mut self, - input_outpoints: Vec<(Outpoint, u64, Terminal)>, - beneficiaries: Vec<&PsbtBeneficiary>, - tx_params: TxParams, - ) -> (Psbt, PsbtMeta) { - let mut psbt = Psbt::create(PsbtVer::V2); - - for (outpoint, value, terminal) in input_outpoints { - psbt.construct_input_expect( - Prevout::new(outpoint, Sats::from(value)), - self.wallet.wallet().descriptor(), - terminal, - tx_params.seq_no, - ); - } - if psbt.inputs().count() == 0 { - panic!("no inputs"); - } - - let input_value = psbt.input_sum(); - let mut max = Vec::new(); - let mut output_value = Sats::ZERO; - for beneficiary in beneficiaries { - let amount = beneficiary.amount.unwrap_or(Sats::ZERO); - output_value.checked_add_assign(amount).unwrap(); - let out = psbt.construct_output_expect(beneficiary.script_pubkey(), amount); - if beneficiary.amount.is_max() { - max.push(out.index()); - } - } - let mut remaining_value = input_value - .checked_sub(output_value) - .unwrap() - .checked_sub(tx_params.fee) - .unwrap(); - if !max.is_empty() { - let portion = remaining_value / max.len(); - for out in psbt.outputs_mut() { - if max.contains(&out.index()) { - out.amount = portion; - } - } - remaining_value = Sats::ZERO; - } - - let (change_vout, change_terminal) = if remaining_value > Sats::from(546u64) { - let change_index = self - .wallet - .wallet_mut() - .next_derivation_index(tx_params.change_keychain, tx_params.change_shift); - let change_terminal = Terminal::new(tx_params.change_keychain, change_index); - let change_vout = psbt - .construct_change_expect( - self.wallet.wallet().descriptor(), - change_terminal, - remaining_value, - ) - .index(); - ( - Some(Vout::from_u32(change_vout as u32)), - Some(change_terminal), - ) - } else { - (None, None) - }; - - ( - psbt, - PsbtMeta { - change_vout, - change_terminal, - }, - ) - } - - fn _construct_beneficiaries( - &self, - beneficiaries: Vec<(Address, Option)>, - ) -> Vec { - beneficiaries - .into_iter() - .map(|(addr, amt)| { - let payment = if let Some(amt) = amt { - Payment::Fixed(Sats::from_sats(amt)) - } else { - Payment::Max - }; - PsbtBeneficiary::new(addr, payment) - }) - .collect() - } - - pub fn construct_psbt_offchain( - &mut self, - input_outpoints: Vec<(Outpoint, u64, Terminal)>, - beneficiaries: Vec<(Address, Option)>, - fee: Option, - ) -> (Psbt, PsbtMeta) { - let tx_params = TxParams::with(Sats::from_sats(fee.unwrap_or(DEFAULT_FEE_ABS))); - let beneficiaries = self._construct_beneficiaries(beneficiaries); - let beneficiaries: Vec<&PsbtBeneficiary> = beneficiaries.iter().collect(); - - self._construct_psbt_offchain(input_outpoints, beneficiaries, tx_params) - } - - pub fn construct_psbt( - &mut self, - input_outpoints: Vec, - beneficiaries: Vec<(Address, Option)>, - fee: Option, - ) -> (Psbt, PsbtMeta) { - let tx_params = TxParams::with(Sats::from_sats(fee.unwrap_or(DEFAULT_FEE_ABS))); - let beneficiaries = self._construct_beneficiaries(beneficiaries); - let beneficiaries: Vec<&PsbtBeneficiary> = beneficiaries.iter().collect(); - - self.wallet - .wallet_mut() - .construct_psbt(input_outpoints, beneficiaries, tx_params) - .unwrap() - } - - pub fn psbt_add_input(&self, psbt: &mut Psbt, utxo: Outpoint) { - for account in self.descriptor.xpubs() { - psbt.xpubs.insert(*account.xpub(), account.origin().clone()); - } - let input = self.wallet.wallet().utxo(utxo).unwrap(); - psbt.construct_input_expect( - input.to_prevout(), - self.wallet.wallet().descriptor(), - input.terminal, - SeqNo::ZERO, - ); - } - - pub fn color_psbt( - &self, - psbt: &mut Psbt, - coloring_info: ColoringInfo, - ) -> (Fascia, AssetBeneficiariesMap) { - let asset_beneficiaries = self.color_psbt_init(psbt, coloring_info); - psbt.complete_construction(); - let fascia = psbt.rgb_commit().unwrap(); - (fascia, asset_beneficiaries) - } - - pub fn color_psbt_init( - &self, - psbt: &mut Psbt, - coloring_info: ColoringInfo, - ) -> AssetBeneficiariesMap { - if !psbt.outputs().any(|o| o.script.is_op_return()) { - let _output = psbt.construct_output_expect(ScriptPubkey::op_return(&[]), Sats::ZERO); - } - - let prev_outputs = psbt - .to_unsigned_tx() - .inputs - .iter() - .map(|txin| txin.prev_output) - .map(|outpoint| XOutpoint::from(XChain::Bitcoin(outpoint))) - .collect::>(); - - let mut all_transitions: HashMap = HashMap::new(); - let mut asset_beneficiaries: AssetBeneficiariesMap = bmap![]; - let assignment_name = FieldName::from("assetOwner"); - - for (contract_id, asset_coloring_info) in coloring_info.asset_info_map.clone() { - let mut asset_transition_builder = self - .wallet - .stock() - .transition_builder(contract_id, asset_coloring_info.iface, None::<&str>) - .unwrap(); - let assignment_id = asset_transition_builder - .assignments_type(&assignment_name) - .unwrap(); - - let mut asset_available_amt = 0; - for (_, opout_state_map) in self - .wallet - .stock() - .contract_assignments_for( - contract_id, - prev_outputs - .iter() - // only retrieve assignments for owned prevouts using coloring_info - .filter(|xop| { - coloring_info.asset_info_map[&contract_id] - .input_outpoints - .contains(xop.as_reduced_unsafe()) - }) - .copied(), - ) - .unwrap() - { - for (opout, state) in opout_state_map { - if let PersistedState::Amount(amt, _, _) = &state { - asset_available_amt += amt.value(); - } - asset_transition_builder = - asset_transition_builder.add_input(opout, state).unwrap(); - } - } - - let mut beneficiaries = vec![]; - let mut sending_amt = 0; - for (vout, amount) in asset_coloring_info.output_map { - if amount == 0 { - continue; - } - sending_amt += amount; - if vout as usize > psbt.outputs().count() { - panic!("invalid vout in output_map, does not exist in the given PSBT"); - } - let graph_seal = if let Some(blinding) = asset_coloring_info.static_blinding { - GraphSeal::with_blinded_vout(CloseMethod::OpretFirst, vout, blinding) - } else { - GraphSeal::new_random_vout(CloseMethod::OpretFirst, vout) - }; - let seal = BuilderSeal::Revealed(XChain::with(Layer1::Bitcoin, graph_seal)); - beneficiaries.push(seal); - - let blinding_factor = if let Some(blinding) = asset_coloring_info.static_blinding { - let mut blinding_32_bytes: [u8; 32] = [0; 32]; - blinding_32_bytes[0..8].copy_from_slice(&blinding.to_le_bytes()); - BlindingFactor::try_from(blinding_32_bytes).unwrap() - } else { - BlindingFactor::random() - }; - asset_transition_builder = asset_transition_builder - .add_fungible_state_raw(assignment_id, seal, amount, blinding_factor) - .unwrap(); - } - if sending_amt > asset_available_amt { - panic!("total amount in output_map greater than available ({asset_available_amt})"); - } - - if let Some(nonce) = coloring_info.nonce { - asset_transition_builder = asset_transition_builder.set_nonce(nonce); - } - - let transition = asset_transition_builder.complete_transition().unwrap(); - all_transitions.insert(contract_id, transition); - asset_beneficiaries.insert(contract_id, beneficiaries); - } - - let (opreturn_index, _) = psbt - .to_unsigned_tx() - .outputs - .iter() - .enumerate() - .find(|(_, o)| o.script_pubkey.is_op_return()) - .expect("psbt should have an op_return output"); - let (_, opreturn_output) = psbt - .outputs_mut() - .enumerate() - .find(|(i, _)| i == &opreturn_index) - .unwrap(); - opreturn_output.set_opret_host().unwrap(); - if let Some(blinding) = coloring_info.static_blinding { - opreturn_output.set_mpc_entropy(blinding).unwrap(); - } - - let tx_inputs = psbt.clone().to_unsigned_tx().inputs; - for (contract_id, transition) in all_transitions { - for (input, txin) in psbt.inputs_mut().zip(&tx_inputs) { - let prevout = txin.prev_output; - let outpoint = Outpoint::new(prevout.txid.to_byte_array().into(), prevout.vout); - if coloring_info - .asset_info_map - .clone() - .get(&contract_id) - .unwrap() - .input_outpoints - .contains(&outpoint) - { - input - .set_rgb_consumer(contract_id, transition.id()) - .unwrap(); - } - } - psbt.push_rgb_transition(transition, CloseMethod::OpretFirst) - .unwrap(); - } - - asset_beneficiaries - } - - pub fn consume_fascia(&mut self, fascia: Fascia, witness_txid: Txid) { - struct FasciaResolver { - witness_id: XWitnessId, - } - impl ResolveWitness for FasciaResolver { - fn resolve_pub_witness( - &self, - _: XWitnessId, - ) -> Result { - unreachable!() - } - fn resolve_pub_witness_ord( - &self, - witness_id: XWitnessId, - ) -> Result { - assert_eq!(witness_id, self.witness_id); - Ok(WitnessOrd::Tentative) - } - } - - let resolver = FasciaResolver { - witness_id: XChain::Bitcoin(witness_txid), - }; - - self.wallet - .stock_mut() - .consume_fascia(fascia, resolver) - .unwrap(); - } - - pub fn update_witnesses(&mut self, after_height: u32) { - let resolver = self.get_resolver(); - self.wallet - .stock_mut() - .update_witnesses(resolver, after_height) - .unwrap(); - } - - pub fn create_consignments( - &self, - asset_beneficiaries: AssetBeneficiariesMap, - witness_txid: Txid, - ) -> Vec { - let mut transfers = vec![]; - let stock = self.wallet.stock(); - - for (contract_id, beneficiaries) in asset_beneficiaries { - for beneficiary in beneficiaries { - match beneficiary { - BuilderSeal::Revealed(seal) => { - let explicit_seal = XChain::Bitcoin(ExplicitSeal::new( - seal.method(), - Outpoint::new(witness_txid, seal.as_reduced_unsafe().vout), - )); - transfers.push(stock.transfer(contract_id, [explicit_seal], None).unwrap()); - } - BuilderSeal::Concealed(seal) => { - transfers.push(stock.transfer(contract_id, vec![], Some(seal)).unwrap()); - } - } - } - } - transfers - } -} diff --git a/tests/utils/mod.rs b/tests/utils/mod.rs index 256c139..505f6ef 100644 --- a/tests/utils/mod.rs +++ b/tests/utils/mod.rs @@ -1,7 +1,12 @@ pub mod chain; -pub mod helpers; +pub mod helper; pub const TEST_DATA_DIR: &str = "test-data"; +pub const SCHEMATA_DIR: &str = "tests/templates/schemata"; +pub const ISSUANCE_DIR: &str = "tests/templates/issuance"; +pub const NON_INFLATABLE_ASSET_TEMPLATE_PATH: &str = "tests/templates/issuance/NFA.yaml"; +pub const FRACTIONAL_UNIQUE_ASSET_TEMPLATE_PATH: &str = "tests/templates/issuance/FUA.yaml"; +pub const FRACTIONABLE_ASSET_COLLECTION_TEMPLATE_PATH: &str = "tests/templates/issuance/FAC.yaml"; pub const INTEGRATION_DATA_DIR: &str = "integration"; pub const STRESS_DATA_DIR: &str = "stress"; @@ -9,9 +14,9 @@ pub const ELECTRUM_1_REGTEST_URL: &str = "127.0.0.1:50001"; pub const ELECTRUM_2_REGTEST_URL: &str = "127.0.0.1:50002"; pub const ELECTRUM_3_REGTEST_URL: &str = "127.0.0.1:50003"; pub const ELECTRUM_MAINNET_URL: &str = "ssl://electrum.iriswallet.com:50003"; -pub const ESPLORA_1_REGTEST_URL: &str = "http://127.0.0.1:8094/regtest/api"; -pub const ESPLORA_2_REGTEST_URL: &str = "http://127.0.0.1:8095/regtest/api"; -pub const ESPLORA_3_REGTEST_URL: &str = "http://127.0.0.1:8096/regtest/api"; +pub const ESPLORA_1_REGTEST_URL: &str = "http://127.0.0.1:3001"; +pub const ESPLORA_2_REGTEST_URL: &str = "http://127.0.0.1:3002"; +pub const ESPLORA_3_REGTEST_URL: &str = "http://127.0.0.1:3003"; pub const ESPLORA_MAINNET_URL: &str = "https://blockstream.info/api"; pub const FAKE_TXID: &str = "e5a3e577309df31bd606f48049049d2e1e02b048206ba232944fcc053a176ccb:0"; pub const UDA_FIXED_INDEX: u32 = 0; @@ -27,13 +32,17 @@ pub use std::{ env::VarError, ffi::OsString, fmt::{self, Display}, - fs::OpenOptions, + fs::{File, OpenOptions}, io::Write, num::NonZeroU32, - path::{PathBuf, MAIN_SEPARATOR}, + ops::Deref, + path::{Path, PathBuf, MAIN_SEPARATOR}, process::{Command, Stdio}, str::FromStr, - sync::{Mutex, Once, OnceLock, RwLock}, + sync::{ + atomic::{AtomicU32, Ordering}, + Mutex, Once, OnceLock, RwLock, + }, time::{Duration, Instant}, }; @@ -42,10 +51,9 @@ pub use amplify::{ confinement::{Confined, U16}, map, s, ByteArray, Wrapper, }; -use bitcoin_hashes::{sha256, Hash}; +pub use bitcoin_hashes::{sha256, Hash}; pub use bp::{ - seals::txout::{BlindSeal, CloseMethod, ExplicitSeal}, - ConsensusDecode, Outpoint, Sats, ScriptPubkey, SeqNo, Tx, Txid, Vout, + seals::WTxoSeal, ConsensusDecode, Outpoint, Sats, ScriptPubkey, SeqNo, Tx, Txid, Vout, }; pub use bpstd::{ h, signers::TestnetSigner, Address, DerivationPath, DerivationSeg, DerivedAddr, Descriptor, @@ -53,60 +61,66 @@ pub use bpstd::{ XpubDerivable, XpubFp, }; pub use bpwallet::{ - fs::FsTextStore, indexers::esplora::Client as EsploraClient, AnyIndexer, Indexer as BpIndexer, - Wallet, + fs::FsTextStore, indexers::esplora::Client as EsploraClient, seals::TxoSeal, AnyIndexer, + Indexer as BpIndexer, Wallet, }; +pub use commit_verify::{Digest, DigestExt, Sha256}; pub use descriptors::Wpkh; pub use electrum::{Client as ElectrumClient, ElectrumApi, Param}; pub use file_format::FileFormat; pub use ifaces::{ - rgb20, rgb21, - rgb21::{EmbeddedMedia, TokenData}, - rgb25, IssuerWrapper, Rgb20, Rgb21, Rgb25, + AssetName, Attachment, Details, EmbeddedMedia, MediaType, Nft, NftSpec, ProofOfReserves, + Ticker, TokenNo, }; +pub use indexmap::IndexMap; pub use once_cell::sync::Lazy; pub use psbt::{ - Beneficiary as PsbtBeneficiary, Payment, Prevout, Psbt, PsbtConstructor, PsbtMeta, PsbtVer, + Beneficiary as PsbtBeneficiary, Payment as PaymentAmount, Prevout, Psbt, PsbtConstructor, + PsbtMeta, PsbtVer, TxParams, }; -pub use psrgbt::{RgbExt, RgbInExt, RgbPsbt, TxParams}; pub use rand::RngCore; pub use rgb::{ - info::ContractInfo, - interface::{AllocatedState, AssignmentsFilter, ContractOp, OpDirection}, - invoice::Pay2Vout, - persistence::{MemContract, MemContractState, Stock}, - resolvers::AnyResolver, - stl::ContractTerms, - validation::{Failure, ResolveWitness, Scripts, Validity, WitnessResolverError}, - vm::{WitnessOrd, WitnessPos, XWitnessTx}, - BlindingFactor, DescriptorRgb, GenesisSeal, GraphSeal, Identity, OpId, RgbDescr, RgbKeychain, - RgbWallet, TapretKey, TransferParams, Transition, WalletProvider, XOutpoint, XWitnessId, + invoice::{RgbBeneficiary, RgbInvoice}, + popls::bp::{Coinselect, OpRequestSet, PaymentScript, PrefabBundle, RgbWallet, WalletProvider}, + AuthToken, CallScope, CellAddr, CodexId, Consensus, ContractId, Contracts, CreateParams, + EitherSeal, Issuer, RgbSealDef, StateCalc, }; -pub use rgbstd::{ - containers::{ - BuilderSeal, ConsignmentExt, Fascia, FileContent, IndexedConsignment, Kit, Transfer, - ValidKit, - }, - interface::{ - ContractBuilder, ContractIface, DataAllocation, FilterExclude, FungibleAllocation, Iface, - IfaceClass, IfaceId, IfaceImpl, NamedField, - }, - invoice::{Beneficiary, RgbInvoice, RgbInvoiceBuilder, XChainNet}, - persistence::{fs::FsBinStore, PersistedState, SchemaIfaces, StashReadProvider}, - schema::SchemaId, - stl::{ - AssetSpec, Attachment, Details, MediaType, Name, ProofOfReserves, RicardianContract, Ticker, - }, - Allocation, Amount, ContractId, GlobalStateType, KnownState, Layer1, Operation, - OutputAssignment, OwnedFraction, Precision, Schema, TokenIndex, TxoSeal, XChain, +pub use rgb_persist_fs::StockpileDir; +use rgbp::Payment; +pub use rgbp::{ + descriptor::RgbDescr, CoinselectStrategy, Owner, PayError, RgbRuntime, RgbpRuntimeDir, }; +pub use rgpsbt::ScriptResolver; pub use rstest::rstest; -pub use schemata::{CollectibleFungibleAsset, NonInflatableAsset, UniqueDigitalAsset}; pub use serial_test::serial; -pub use strict_encoding::{fname, tn, FieldName, StrictSerialize, TypeName}; -pub use strict_types::{StrictVal, TypeSystem}; +use std::convert::Infallible; +pub use strict_encoding::{fname, tn, StrictSerialize}; +pub use strict_types::{ + value::{Blob, StrictNum, StrictVal}, + FieldName, TypeName, TypeSystem, VariantName, +}; pub use strum::IntoEnumIterator; pub use strum_macros::EnumIter; +pub use tabled::{ + settings::{object::Columns, Alignment, Modify, Style}, + Table, Tabled, +}; pub use time::OffsetDateTime; -pub use crate::utils::{chain::*, helpers::*}; +pub const KEY_CHAIN_RGB: u8 = 9; +pub const KEY_CHAIN_TAPRET: u8 = 10; + +pub use helper::asset_params::AssetParamsBuilder; +pub use helper::asset_types::{ + attachment_from_fpath, nft_spec, nft_spec_minimal, FACIssueParams, FUAIssueParams, + NIAIssueParams, +}; +pub use helper::coinselect::CustomCoinselectStrategy; +pub use helper::reporting::Report; +pub use helper::wallet::{DescriptorType, InvoiceType, TestWallet, TransferType}; + +pub use chain::{fund_wallet, indexer_url, is_tx_confirmed, mine_custom, Indexer, INDEXER}; +pub use helper::asset_types::{ContractImmutableState, ContractOwnedState, ContractState}; +pub use rgb::{Assignment, NamedState, StateAtom}; +pub use rgb::{ConsumeError, ImmutableState, OwnedState, StateName}; +pub use strict_types::value::EnumTag; diff --git a/tests/validation.rs b/tests/validation.rs deleted file mode 100644 index 6049d92..0000000 --- a/tests/validation.rs +++ /dev/null @@ -1,401 +0,0 @@ -pub mod utils; - -use utils::*; - -enum MockResolvePubWitness { - Success(Tx), - Error(WitnessResolverError), -} - -enum MockResolvePubWitnessOrd { - Success(WitnessOrd), - Error(WitnessResolverError), -} - -struct MockResolver { - pub_witnesses: HashMap, - pub_witness_ords: HashMap, -} - -impl ResolveWitness for MockResolver { - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result { - if let Some(res) = self.pub_witnesses.get(&witness_id) { - match res { - MockResolvePubWitness::Success(tx) => Ok(XChain::Bitcoin(tx.clone())), - MockResolvePubWitness::Error(err) => Err(err.clone()), - } - } else { - Err(WitnessResolverError::Unknown(witness_id)) - } - } - - fn resolve_pub_witness_ord( - &self, - witness_id: XWitnessId, - ) -> Result { - if let Some(res) = self.pub_witness_ords.get(&witness_id) { - match res { - MockResolvePubWitnessOrd::Success(witness_ord) => Ok(*witness_ord), - MockResolvePubWitnessOrd::Error(err) => Err(err.clone()), - } - } else { - Err(WitnessResolverError::Unknown(witness_id)) - } - } -} - -#[derive(Debug, EnumIter, Copy, Clone, PartialEq)] -enum Scenario { - A, - B, -} - -impl fmt::Display for Scenario { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -impl Scenario { - fn resolver(&self) -> MockResolver { - match self { - Self::A => { - let (tx_1, witness_id_1) = - get_tx("bc:a5c3085efe8dfdba0fa0e11d81bf90cdcac27c0af496c4de1a2fd9659948ffce"); - let (tx_2, witness_id_2) = - get_tx("bc:d077ea7e3a55a215893a18e82cb03fda0f50619893e4aee0ba70b014e6d63248"); - let (tx_3, witness_id_3) = - get_tx("bc:3652d9fea802cb051f671455cbd7472e3bce2c440a4e54fa4321107037dfaff0"); - MockResolver { - pub_witnesses: map![ - witness_id_1 => MockResolvePubWitness::Success(tx_1), - witness_id_2 => MockResolvePubWitness::Success(tx_2), - witness_id_3 => MockResolvePubWitness::Success(tx_3), - ], - pub_witness_ords: map![ - witness_id_1 => MockResolvePubWitnessOrd::Success(WitnessOrd::Mined(WitnessPos::bitcoin(NonZeroU32::new(106).unwrap(), 1726062111).unwrap())), - witness_id_2 => MockResolvePubWitnessOrd::Success(WitnessOrd::Mined(WitnessPos::bitcoin(NonZeroU32::new(108).unwrap(), 1726062111).unwrap())), - witness_id_3 => MockResolvePubWitnessOrd::Success(WitnessOrd::Mined(WitnessPos::bitcoin(NonZeroU32::new(110).unwrap(), 1726062112).unwrap())), - ], - } - } - Self::B => { - let (tx_1, witness_id_1) = - get_tx("bc:c269055b7750a234087c11acd7a408172cb84d8fc6af0ded42d8a8cbea6712e9"); - let (tx_2, witness_id_2) = - get_tx("bc:d84c37b6c6616184c454c815d970505bed9b3a3723a4445dd1289dc708bc80b3"); - let (tx_3, witness_id_3) = - get_tx("bc:0bc3024ce6404cd7aea387debde687d9e8731228e16b04b4eefda7283069f1c3"); - MockResolver { - pub_witnesses: map![ - witness_id_1 => MockResolvePubWitness::Success(tx_1), - witness_id_2 => MockResolvePubWitness::Success(tx_2), - witness_id_3 => MockResolvePubWitness::Success(tx_3), - ], - pub_witness_ords: map![ - witness_id_1 => MockResolvePubWitnessOrd::Success(WitnessOrd::Mined(WitnessPos::bitcoin(NonZeroU32::new(105).unwrap(), 1726062423).unwrap())), - witness_id_2 => MockResolvePubWitnessOrd::Success(WitnessOrd::Mined(WitnessPos::bitcoin(NonZeroU32::new(106).unwrap(), 1726062423).unwrap())), - witness_id_3 => MockResolvePubWitnessOrd::Success(WitnessOrd::Mined(WitnessPos::bitcoin(NonZeroU32::new(106).unwrap(), 1726062423).unwrap())), - ], - } - } - } - } -} - -fn get_consignment(scenario: Scenario) -> (Transfer, Vec) { - initialize(); - - let transfer_type = match scenario { - Scenario::A => TransferType::Blinded, - Scenario::B => TransferType::Witness, - }; - - let mut wlt_1 = get_wallet(&DescriptorType::Wpkh); - let mut wlt_2 = get_wallet(&DescriptorType::Wpkh); - - let issued_supply_1 = 999; - let issued_supply_2 = 666; - - let sats = 9000; - - let utxo = wlt_1.get_utxo(None); - let (contract_id_1, iface_type_name_1) = - wlt_1.issue_nia(issued_supply_1, wlt_1.close_method(), Some(&utxo)); - let (contract_id_2, iface_type_name_2) = - wlt_1.issue_nia(issued_supply_2, wlt_1.close_method(), Some(&utxo)); - - let mut txes = vec![]; - - let (_consignment, tx) = wlt_1.send( - &mut wlt_2, - transfer_type, - contract_id_1, - &iface_type_name_1, - 66, - sats, - None, - ); - txes.push(tx); - - // spend asset moved with blank transition - let (_consignment, tx) = wlt_1.send( - &mut wlt_2, - transfer_type, - contract_id_2, - &iface_type_name_2, - 50, - sats, - None, - ); - txes.push(tx); - - // spend change of previous send - let (consignment, tx) = wlt_1.send( - &mut wlt_2, - transfer_type, - contract_id_2, - &iface_type_name_2, - 77, - sats, - None, - ); - txes.push(tx); - - (consignment, txes) -} - -// run once to generate tests/fixtures/consignemnt_.yaml -// for example: -// SCENARIO=B cargo test --test validation validate_consignment_generate -- --ignored --show-output -// -// then copy the generated consignemnt file to tests/fixtures/attack_.yaml -// manually change tests/fixtures/attack_.yaml files to simulate attacks -#[test] -#[ignore = "one-shot"] -fn validate_consignment_generate() { - let scenario = match std::env::var("SCENARIO") { - Ok(val) if val.to_uppercase() == Scenario::A.to_string() => Scenario::A, - Ok(val) if val.to_uppercase() == Scenario::B.to_string() => Scenario::B, - Err(VarError::NotPresent) => Scenario::A, - _ => panic!("invalid scenario"), - }; - let (consignment, txes) = get_consignment(scenario); - println!(); - let cons_path = format!("tests/fixtures/consignment_{scenario}.yaml"); - let yaml = serde_yaml::to_string(&consignment).unwrap(); - std::fs::write(&cons_path, yaml).unwrap(); - println!("written consignment in: {cons_path}"); - for tx in txes { - let txid = tx.txid().to_string(); - let witness_id = XWitnessId::from_str(&txid).unwrap(); - let normalized_witness_id = witness_id.to_string().replace(":", "_"); - let yaml = serde_yaml::to_string(&tx).unwrap(); - let yaml_path = format!("tests/fixtures/{normalized_witness_id}.yaml"); - std::fs::write(&yaml_path, yaml).unwrap(); - println!("written tx: {witness_id}"); - } -} - -fn get_consignment_from_yaml(fname: &str) -> Transfer { - let cons_path = format!("tests/fixtures/{fname}.yaml"); - println!("loading {cons_path}"); - let file = std::fs::File::open(cons_path).unwrap(); - let consignment: Transfer = serde_yaml::from_reader(file).unwrap(); - consignment -} - -fn get_tx(witness_id: &str) -> (Tx, XWitnessId) { - let normalized_witness_id = witness_id.replace(":", "_"); - let yaml_path = format!("tests/fixtures/{normalized_witness_id}.yaml"); - let file = std::fs::File::open(yaml_path).unwrap(); - let tx: Tx = serde_yaml::from_reader(file).unwrap(); - let xwitness_id = XWitnessId::from_str(witness_id).unwrap(); - (tx, xwitness_id) -} - -#[test] -fn validate_consignment_success() { - for scenario in Scenario::iter() { - let resolver = scenario.resolver(); - let consignment = get_consignment_from_yaml(&format!("consignment_{scenario}")); - let res = consignment.validate(&resolver, true); - assert!(res.is_ok()); - let validation_status = match res { - Ok(validated_consignment) => validated_consignment.validation_status().clone(), - Err((status, _consignment)) => status, - }; - dbg!(&validation_status); - assert!(validation_status.failures.is_empty()); - assert!(validation_status.warnings.is_empty()); - assert!(validation_status.info.is_empty()); - let validity = validation_status.validity(); - assert_eq!(validity, Validity::Valid); - } -} - -#[test] -fn validate_consignment_chain_fail() { - let resolver = Scenario::A.resolver(); - - // liquid - let consignment = get_consignment_from_yaml("attack_chain"); - let res = consignment.validate(&resolver, true); - assert!(res.is_err()); - let validation_status = match res { - Ok(validated_consignment) => validated_consignment.validation_status().clone(), - Err((status, _consignment)) => status, - }; - dbg!(&validation_status); - assert!(validation_status.warnings.is_empty()); - assert!(validation_status.info.is_empty()); - let validity = validation_status.validity(); - assert_eq!(validity, Validity::Invalid); -} - -#[test] -fn validate_consignment_genesis_fail() { - let resolver = Scenario::B.resolver(); - - // schema ID: change genesis[schemaId] with CFA schema ID - let consignment = get_consignment_from_yaml("attack_genesis_schema_id"); - let res = consignment.validate(&resolver, true); - assert!(res.is_err()); - let validation_status = match res { - Ok(validated_consignment) => validated_consignment.validation_status().clone(), - Err((status, _consignment)) => status, - }; - dbg!(&validation_status); - assert_eq!(validation_status.failures.len(), 5); - assert!(matches!( - validation_status.failures[0], - Failure::OperationAbsent(_) - )); - assert!(matches!( - validation_status.failures[1], - Failure::MpcInvalid(_, _, _) - )); - assert!(matches!( - validation_status.failures[2], - Failure::BundleExtraTransition(_, _) - )); - assert!(matches!( - validation_status.failures[3], - Failure::MpcInvalid(_, _, _) - )); - assert!(matches!( - validation_status.failures[4], - Failure::MpcInvalid(_, _, _) - )); - assert!(validation_status.warnings.is_empty()); - assert!(validation_status.info.is_empty()); - let validity = validation_status.validity(); - assert_eq!(validity, Validity::Invalid); - - // genesis testnet: change from true to false - let consignment = get_consignment_from_yaml("attack_genesis_testnet"); - let res = consignment.validate(&resolver, true); - assert!(res.is_err()); - let validation_status = match res { - Ok(validated_consignment) => validated_consignment.validation_status().clone(), - Err((status, _consignment)) => status, - }; - dbg!(&validation_status); - assert_eq!(validation_status.failures.len(), 1); - assert!(matches!( - validation_status.failures[0], - Failure::NetworkMismatch(_) - )); - assert!(validation_status.warnings.is_empty()); - assert!(validation_status.info.is_empty()); - let validity = validation_status.validity(); - assert_eq!(validity, Validity::Invalid); -} - -#[test] -fn validate_consignment_bundles_fail() { - let resolver = Scenario::A.resolver(); - - // bundles pubWitness data inputs[0] sequence: change from 0 to 1 - let consignment = get_consignment_from_yaml("attack_bundles_pubWitness_data_input_sequence"); - let res = consignment.validate(&resolver, true); - assert!(res.is_err()); - let validation_status = match res { - Ok(validated_consignment) => validated_consignment.validation_status().clone(), - Err((status, _consignment)) => status, - }; - dbg!(&validation_status); - assert_eq!(validation_status.failures.len(), 3); - assert!(matches!( - validation_status.failures[0], - Failure::SealsInvalid(_, _, _) - )); - assert!(matches!( - validation_status.failures[1], - Failure::BundleInvalidCommitment(_, _, _, _) - )); - assert!(matches!( - validation_status.failures[2], - Failure::SealNoPubWitness(_, _, _) - )); - assert!(validation_status.warnings.is_empty()); - assert!(validation_status.info.is_empty()); - let validity = validation_status.validity(); - assert_eq!(validity, Validity::Invalid); -} - -#[test] -fn validate_consignment_resolver_error() { - let scenario = Scenario::A; - let mut resolver = scenario.resolver(); - let txid = - Txid::from_str("d077ea7e3a55a215893a18e82cb03fda0f50619893e4aee0ba70b014e6d63248").unwrap(); - let xwitness_id = XChain::Bitcoin(txid); - - // resolve_pub_witness error - *resolver.pub_witnesses.get_mut(&xwitness_id).unwrap() = MockResolvePubWitness::Error( - WitnessResolverError::Other(xwitness_id, s!("unexpected error")), - ); - let consignment = get_consignment_from_yaml("attack_resolver_error"); - let res = consignment.validate(&resolver, true); - assert!(res.is_err()); - let validation_status = match res { - Ok(validated_consignment) => validated_consignment.validation_status().clone(), - Err((status, _consignment)) => status, - }; - dbg!(&validation_status); - assert_eq!(validation_status.failures.len(), 1); - assert!(matches!( - validation_status.failures[0], - Failure::SealNoPubWitness(_, _, _) - )); - assert!(validation_status.warnings.is_empty()); - assert!(validation_status.info.is_empty()); - let validity = validation_status.validity(); - assert_eq!(validity, Validity::Invalid); - - // resolve_pub_witness_ord error - *resolver.pub_witness_ords.get_mut(&xwitness_id).unwrap() = MockResolvePubWitnessOrd::Error( - WitnessResolverError::Other(xwitness_id, s!("unexpected error")), - ); - let consignment = get_consignment_from_yaml("attack_resolver_error"); - let res = consignment.validate(&resolver, true); - assert!(res.is_err()); - let validation_status = match res { - Ok(validated_consignment) => validated_consignment.validation_status().clone(), - Err((status, _consignment)) => status, - }; - dbg!(&validation_status); - assert_eq!(validation_status.failures.len(), 1); - assert!(matches!( - validation_status.failures[0], - Failure::SealNoPubWitness(_, _, _) - )); - assert!(validation_status.warnings.is_empty()); - assert!(validation_status.info.is_empty()); - let validity = validation_status.validity(); - assert_eq!(validity, Validity::Invalid); -} diff --git a/ultrasonic b/ultrasonic new file mode 160000 index 0000000..36ee081 --- /dev/null +++ b/ultrasonic @@ -0,0 +1 @@ +Subproject commit 36ee081936420f189b160321e56cdc1175848f35 diff --git a/vesper b/vesper index 6e1c889..0f0e7a2 160000 --- a/vesper +++ b/vesper @@ -1 +1 @@ -Subproject commit 6e1c889e9b951ac709d7db0e57d02dc427446527 +Subproject commit 0f0e7a2a6858b7eb13ec03199379772377d41856 diff --git a/zk-aluvm b/zk-aluvm new file mode 160000 index 0000000..5120662 --- /dev/null +++ b/zk-aluvm @@ -0,0 +1 @@ +Subproject commit 5120662cfaaf271e36885a768d404b7fcbcd17f2