diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5708a9d0..d03f9a47 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,7 +65,7 @@ jobs: strategy: fail-fast: false matrix: - toolchain: [ nightly, beta, stable, 1.77.0 ] + toolchain: [ nightly, beta, stable, 1.81.0 ] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 81ede7ef..85f53a4b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,4 +37,4 @@ jobs: - name: Add wasm32 target run: rustup target add wasm32-unknown-unknown - name: Test in headless Chrome - run: wasm-pack test --headless --chrome + run: RUSTFLAGS='--cfg getrandom_backend="wasm_js"' wasm-pack test --headless --chrome diff --git a/Cargo.lock b/Cargo.lock index 92fda88f..e3e3eebf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,15 +13,15 @@ dependencies = [ [[package]] name = "aluvm" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2a6767842958f458dc7010a2a1005db96dfaceadd366d07532c5045bbc81f24" +checksum = "6035110db4d2f0a0e6df87e7b61f1c397828ed127ed97d46896371a258888403" dependencies = [ "amplify", "ascii-armor", "baid64", "blake3", - "getrandom", + "getrandom 0.3.2", "half", "paste", "ripemd", @@ -34,16 +34,16 @@ dependencies = [ [[package]] name = "amplify" -version = "4.7.1" +version = "4.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2090b9b79b61d4047a307a46de043d0ee5ec406d99a7d652341b96d48ed5567" +checksum = "3a9d7cb29f1d4c6ec8650abbee35948b8bdefb7f0750a26445ff593eb9bf7fcf" dependencies = [ "amplify_apfloat", "amplify_derive", "amplify_num", "amplify_syn", "ascii", - "rand", + "rand 0.8.5", "serde", "stringly_conversions", "wasm-bindgen", @@ -56,7 +56,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "695e433882668b55b3d7fb0ba22bf9be66a91abe30d7ca1f1a774f8b90b4db4c" dependencies = [ "amplify_num", - "bitflags 2.6.0", + "bitflags", "wasm-bindgen", ] @@ -110,9 +110,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" @@ -149,11 +149,12 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] @@ -180,9 +181,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 = "e4966ac403dc4a666d8131dfe4df684f45acc68d4c7e768db89c463aa5617910" +checksum = "0269eb842ec952b027df0fc33184b6a0dea5ea473160b36992274eb53758461e" dependencies = [ "amplify", "baid64", @@ -199,49 +200,39 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-lc-rs" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd82dba44d209fddb11c190e0a94b78651f95299598e472215667417a03ff1d" +checksum = "19b756939cb2f8dc900aa6dcd505e6e2428e9cae7ff7b028c49e3946efa70878" dependencies = [ "aws-lc-sys", - "mirai-annotations", - "paste", "zeroize", ] [[package]] name = "aws-lc-sys" -version = "0.22.0" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df7a4168111d7eb622a31b214057b8509c0a7e1794f44c546d742330dc793972" +checksum = "bfa9b6986f250236c27e5a204062434a773a13243d2ffc2955f37bdba4c5c6a1" dependencies = [ "bindgen", "cc", "cmake", "dunce", "fs_extra", - "libc", - "paste", ] [[package]] name = "baid64" -version = "0.2.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95dabc2759e01e2c382968639868a701f384a18890934f9e75d4feb4d6623794" +checksum = "6cb4a8b2f1afee4ef00a190b260ad871842b93206177b59631fecd325d48d538" dependencies = [ "amplify", - "base64 0.22.1", + "base64", "mnemonic", "sha2", ] -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - [[package]] name = "base64" version = "0.22.1" @@ -254,7 +245,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36915bbaca237c626689b5bd14d02f2ba7a5a359d30a2a08be697392e3718079" dependencies = [ - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -269,7 +260,7 @@ version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.6.0", + "bitflags", "cexpr", "clang-sys", "itertools", @@ -282,15 +273,15 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.85", + "syn 2.0.101", "which", ] [[package]] name = "bitcoin-io" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" [[package]] name = "bitcoin_hashes" @@ -304,21 +295,15 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "blake3" -version = "1.5.4" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" dependencies = [ "arrayref", "arrayvec", @@ -336,11 +321,17 @@ 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.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40f227ce25d185bc5fc9109ca83dfa8bd0e745f219e320f3da658aaf4fd7e0c5" +checksum = "2d473a0cea358746ab5ef820b62f2530ce6516cb59226c9a3736a8e60c4943d9" dependencies = [ "amplify", "chrono", @@ -353,16 +344,17 @@ dependencies = [ [[package]] name = "bp-core" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c6b213ada98fe5e78a978e67a7044d16d2571edb3f85fcdb4246324ec9514a" +checksum = "d248df4e1ab41de97556bb092891c8c5208604f471a20c4129dc357fd9eade39" dependencies = [ "amplify", "bp-consensus", "bp-dbc", "bp-seals", "commit_verify", - "getrandom", + "getrandom 0.2.16", + "getrandom 0.3.2", "serde", "single_use_seals", "strict_encoding", @@ -372,9 +364,9 @@ dependencies = [ [[package]] name = "bp-dbc" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d33d4cc345a595236441fc2b8726ca7eb693947914b278849d1e2c1923dcb314" +checksum = "2670bd384743ba75ca6d8cf821bcdcb74bfd5715e8798e545331dc00652f612c" dependencies = [ "amplify", "base85", @@ -387,47 +379,48 @@ dependencies = [ [[package]] name = "bp-derive" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ebed0079fc2e75dc238103f0f81fefd2cbbc3120ae55c58fe0aa61dad26ddc" +checksum = "781d974f0bd877627d4242cab38166a879682e32e98fd06809f1ebf4a1119f5f" 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.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43476738e6327bfda9c1d7bcffcdb5f931ad03cbe4dc26fe4087fe505b7d96d2" +checksum = "752903a7ec4bd5a2dc7709f4eb9fc86abe52a702a0f6699bebb79f021f506ec7" dependencies = [ "amplify", - "bp-std", + "bp-core", "byteorder", "libc", "log", - "rustls 0.23.16", + "rustls 0.23.26", "serde", "serde_json", "sha2", - "webpki-roots 0.26.6", + "webpki-roots 0.26.10", "winapi", ] [[package]] name = "bp-esplora" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea6ad8f3ae73ea99517a9eab934a8abf7a1463e562da47dc124b4cd1b16692f" +checksum = "faa310a99982cd5e5a51c070a0a0a4fb9ad4db85767febd476e10bbaf4b52ad1" dependencies = [ "amplify", - "bp-std", + "bp-core", + "bp-invoice", "log", "minreq", "serde", @@ -437,9 +430,9 @@ dependencies = [ [[package]] name = "bp-invoice" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6955d67eec75b22532edb859f1f4d7d4ba4af1db304abc511530f4e1a827b7" +checksum = "d2a2365fc099e265705f31f018d4fb9309546cc3fdb6f855da6d2a81e9700bd2" dependencies = [ "amplify", "bech32", @@ -450,16 +443,16 @@ dependencies = [ [[package]] name = "bp-seals" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a7a009fbf7e71be7ab5f43e032c69927f58cd7f59a6a822af64f84d3e8d41c5" +checksum = "3aab0c94862b08721f7a60eb0d13502605147ebc2fc3cfe0ceacdb6d58aeb43c" dependencies = [ "amplify", "baid64", "bp-consensus", "bp-dbc", "commit_verify", - "rand", + "rand 0.9.1", "serde", "single_use_seals", "strict_encoding", @@ -467,9 +460,9 @@ dependencies = [ [[package]] name = "bp-std" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78d36be2d9ef2f70821c8d73f9f58739d0057f7cba9aa30b05d64247bd8554d" +checksum = "d2949a2d009f91d65e9e95c13625f996b146614fc3d47118b73f2d954f8ee2c3" dependencies = [ "amplify", "bp-consensus", @@ -477,7 +470,8 @@ dependencies = [ "bp-derive", "bp-invoice", "descriptors", - "getrandom", + "getrandom 0.2.16", + "getrandom 0.3.2", "psbt", "secp256k1", "serde", @@ -486,12 +480,12 @@ dependencies = [ [[package]] name = "bp-wallet" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a1ea4b3bca45bfc61613847bd3c2a03c650e4c376c81e584a7e83cd33edbc4f" +checksum = "d42056626fcd7a48d369db0ba68a2aa5a1714fc1ef1a60cb680dbeacb32ad6d7" dependencies = [ "amplify", - "base64 0.22.1", + "base64", "bp-electrum", "bp-esplora", "bp-std", @@ -513,9 +507,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byteorder" @@ -525,9 +519,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.31" +version = "1.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" dependencies = [ "jobserver", "libc", @@ -551,9 +545,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[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", @@ -561,7 +555,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -577,9 +571,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" dependencies = [ "clap_builder", "clap_derive", @@ -587,9 +581,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" dependencies = [ "anstream", "anstyle", @@ -599,27 +593,27 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.101", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "cmake" -version = "0.1.51" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ "cc", ] @@ -632,19 +626,18 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.1.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "commit_encoding_derive" -version = "0.11.0" +version = "0.11.1-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc09678c15e9280cc6eaf29bf437a2cf18fadedd8bf78c369b8ac15fa217dbe5" +checksum = "d12f2e05ae7d81bc49d9f0856ff97968da750bf09f145043155e9c7f13ce4ace" dependencies = [ "amplify", "amplify_syn", @@ -655,13 +648,13 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.11.0" +version = "0.11.1-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcf5f557e112c684f2458f20c66bab865c01cab56d6a318f64243cba9b163a7" +checksum = "171940b95b456f7c8906c78cd548c1dcf30310c4dc2e2a5ba352ac183bf163b3" dependencies = [ "amplify", "commit_encoding_derive", - "rand", + "rand 0.9.1", "ripemd", "serde", "sha2", @@ -670,16 +663,6 @@ dependencies = [ "vesper-lang", ] -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - [[package]] name = "constant_time_eq" version = "0.3.1" @@ -694,18 +677,18 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-common" @@ -719,9 +702,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ "darling_core", "darling_macro", @@ -729,34 +712,34 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.85", + "syn 2.0.101", ] [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.85", + "syn 2.0.101", ] [[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", @@ -764,13 +747,13 @@ dependencies = [ [[package]] name = "descriptors" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb1e86bc1bbf96aa464ae3f8bbec92afc83da40f1470109ce4207d708773d06" +checksum = "937324b35385dad51b2e589b76effd6859968368b1067c8a9f34245f9f7bf68d" dependencies = [ "amplify", "bp-derive", - "indexmap 2.6.0", + "indexmap 2.9.0", "serde", ] @@ -787,23 +770,23 @@ dependencies = [ [[package]] name = "dirs" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -814,15 +797,15 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -830,31 +813,31 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", + "jiff", "log", ] [[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.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -865,11 +848,12 @@ checksum = "a35a73237400bde66c82e38387343f90d7182a2f2f22729e096a2abd57d75db9" [[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]] @@ -896,28 +880,42 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", "wasm-bindgen", ] [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "half" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -931,9 +929,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" [[package]] name = "heck" @@ -967,29 +965,24 @@ 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 = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -1022,12 +1015,12 @@ 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.3", "serde", ] @@ -1048,25 +1041,51 @@ 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 = "jiff" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a064218214dc6a10fbae5ec5fa888d80c45d611aba169222fc272072bf7aef6" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.2", "libc", ] [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1084,18 +1103,18 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.161" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1104,21 +1123,21 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags", "libc", ] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[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" @@ -1134,9 +1153,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minicov" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def6d99771d7c499c26ad4d40eb6645eafd3a1553b35fc26ea5a489a45e82d9a" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" dependencies = [ "cc", "walkdir", @@ -1150,13 +1169,12 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "minreq" -version = "2.13.2" +version = "2.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0c420feb01b9fb5061f8c8f452534361dd783756dcf38ec45191ce55e7a161" +checksum = "f0d2aaba477837b46ec1289588180fabfccf0c3b1d1a0c6b1866240cd6cd5ce9" dependencies = [ - "base64 0.12.3", + "base64", "log", - "once_cell", "rustls 0.21.12", "rustls-webpki 0.101.7", "serde", @@ -1164,12 +1182,6 @@ dependencies = [ "webpki-roots 0.25.4", ] -[[package]] -name = "mirai-annotations" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" - [[package]] name = "mnemonic" version = "1.1.1" @@ -1188,9 +1200,9 @@ dependencies = [ [[package]] name = "nonasync" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b1005555d351f593bf72ffc3a89a0d42e243df004d2c4ded17699f10b562b98" +checksum = "d81f7335a3fa37124e24461d6164485760d4c056dd92a81a70c23fc28c2b63c8" dependencies = [ "amplify", "log", @@ -1213,9 +1225,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "option-ext" @@ -1235,6 +1247,21 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1243,59 +1270,65 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] [[package]] name = "prettyplease" -version = "0.2.25" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" dependencies = [ "proc-macro2", - "syn 2.0.85", + "syn 2.0.101", ] [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "psbt" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a60fcac15e3bd83cbca0388d70ac696f066790e992a5ceb230a04317ae8b991e" +checksum = "c0b76f7da8e1c501ec5ea18eaae8db05304ee1e6b2aa118dac8aae931aa3ee0f" dependencies = [ "amplify", - "base64 0.22.1", + "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.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +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" @@ -1303,8 +1336,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]] @@ -1314,7 +1357,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]] @@ -1323,18 +1376,47 @@ 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.2", ] [[package]] name = "redox_users" -version = "0.4.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom", + "getrandom 0.2.16", "libredox", - "thiserror", + "thiserror 2.0.12", +] + +[[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 = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] @@ -1351,9 +1433,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1368,9 +1450,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rgb-core" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae7debf4fc13bbf2d217f71d29a0233fddf5fc5b148ded64175df36c3635029" +checksum = "eba005ded4929a2d7a6e4cb97103858b9e0d47e9fe7a378ca2b2f1595451d659" dependencies = [ "aluvm", "amplify", @@ -1378,7 +1460,7 @@ dependencies = [ "bp-core", "chrono", "commit_verify", - "getrandom", + "getrandom 0.3.2", "mime", "secp256k1", "serde", @@ -1390,9 +1472,9 @@ dependencies = [ [[package]] name = "rgb-invoice" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d713f88dce2b3ca159150fb9617ed4af2a2b4a785437138e74f74598acd05adb" +checksum = "c74a3dc19886db08f3492634b3a2b978cf722b0014a8c5d6af46a627c1674179" dependencies = [ "amplify", "baid64", @@ -1400,9 +1482,9 @@ dependencies = [ "bp-invoice", "fast32", "fluent-uri", - "indexmap 2.6.0", + "indexmap 2.9.0", "percent-encoding", - "rand", + "rand 0.9.1", "rgb-core", "serde", "strict_encoding", @@ -1411,15 +1493,15 @@ dependencies = [ [[package]] name = "rgb-psbt" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" dependencies = [ "amplify", "baid64", "bp-core", "bp-std", "commit_verify", - "getrandom", - "rand", + "getrandom 0.3.2", + "rand 0.9.1", "rgb-std", "strict_encoding", "wasm-bindgen", @@ -1428,22 +1510,20 @@ dependencies = [ [[package]] name = "rgb-runtime" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" dependencies = [ "amplify", "baid64", "bp-core", - "bp-electrum", - "bp-esplora", "bp-std", "bp-wallet", "chrono", "commit_verify", - "getrandom", - "indexmap 2.6.0", + "getrandom 0.3.2", + "indexmap 2.9.0", "log", "nonasync", - "rand", + "rand 0.9.1", "rgb-psbt", "rgb-std", "serde", @@ -1455,9 +1535,9 @@ dependencies = [ [[package]] name = "rgb-std" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98b5d547e950f138f26c1eeb6ec98d53bc7adb8b96e311e9f1b7ac08252e050" +checksum = "7484c24898614862d547316b631ac8c6bb34f401a56f32249b9d1dd4677dc739" dependencies = [ "aluvm", "amplify", @@ -1465,12 +1545,14 @@ dependencies = [ "baid64", "base85", "bp-core", + "bp-electrum", + "bp-esplora", "chrono", "commit_verify", - "getrandom", - "indexmap 2.6.0", + "getrandom 0.3.2", + "indexmap 2.9.0", "nonasync", - "rand", + "rand 0.9.1", "rgb-core", "rgb-invoice", "serde", @@ -1481,7 +1563,7 @@ dependencies = [ [[package]] name = "rgb-wallet" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" dependencies = [ "amplify", "baid64", @@ -1503,15 +1585,14 @@ dependencies = [ [[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", ] @@ -1533,15 +1614,15 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1558,24 +1639,24 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.16" +version = "0.23.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" dependencies = [ "aws-lc-rs", "log", "once_cell", "rustls-pki-types", - "rustls-webpki 0.102.8", + "rustls-webpki 0.103.1", "subtle", "zeroize", ] [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" [[package]] name = "rustls-webpki" @@ -1589,9 +1670,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.8" +version = "0.103.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" dependencies = [ "aws-lc-rs", "ring", @@ -1599,11 +1680,17 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -1614,12 +1701,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "sct" version = "0.7.1" @@ -1637,7 +1718,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", - "rand", + "rand 0.8.5", "secp256k1-sys", "serde", ] @@ -1653,29 +1734,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.214" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.101", ] [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -1704,15 +1785,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ - "base64 0.22.1", + "base64", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.6.0", + "indexmap 2.9.0", "serde", "serde_derive", "serde_json", @@ -1722,14 +1803,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.101", ] [[package]] @@ -1738,7 +1819,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", @@ -1747,9 +1828,9 @@ dependencies = [ [[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", @@ -1758,9 +1839,9 @@ dependencies = [ [[package]] name = "shellexpand" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" +checksum = "8b1fdf65dd6331831494dd616b30351c38e96e45921a27745cf98490458b90bb" dependencies = [ "dirs", ] @@ -1773,27 +1854,20 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" -version = "0.11.0" +version = "0.11.1-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01aad2d785dc858c4f652d1e18d0c815cd10aa8f15ac7accd2b12b894d7c367" +checksum = "8c36139c6f642d05f2d74501a8f84ccfb5833caeb7c8cde1e6b811261cd526bd" dependencies = [ "amplify_derive", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - [[package]] name = "strict_encoding" -version = "2.7.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d69b4893cf054e129d5288a565102124520d7b94eb9589d1e78202abc7e2092d" +checksum = "8553c0321466c11aa1e33f082c9190194f380efd8824bf5ce4fa56b64b875be9" dependencies = [ "amplify", - "half", "serde", "strict_encoding_derive", "wasm-bindgen", @@ -1801,9 +1875,9 @@ dependencies = [ [[package]] name = "strict_encoding_derive" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4f9b678862372f8e439bcaafc27df7610ea93b06d2deb6244dec0af4259ce6" +checksum = "34e3bc6e4a2450420b4dbfb6929d9ce005e8c36cf73bf215db99f0d09c9fa79f" dependencies = [ "amplify_syn", "heck", @@ -1814,15 +1888,14 @@ dependencies = [ [[package]] name = "strict_types" -version = "2.7.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bae7475fc901144d8a35d25e36d76aa020b840f233d60532d6d52318718781b" +checksum = "07dd1bdf4bfce0a1ff3eec041e7d4d20b06d22ca2aaf71338726dd9609e57a5e" dependencies = [ "amplify", "ascii-armor", "baid64", - "half", - "indexmap 2.6.0", + "indexmap 2.9.0", "serde", "serde_json", "serde_yaml", @@ -1868,9 +1941,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.85" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -1879,29 +1952,49 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.65" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] name = "thiserror-impl" -version = "1.0.65" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.101", ] [[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", @@ -1914,15 +2007,15 @@ 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", @@ -1930,9 +2023,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -1942,37 +2035,44 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[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-ident" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unsafe-libyaml" @@ -2000,9 +2100,9 @@ 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 = "f72ebd3b32f16ee8ace2bd3058c2bfa0f4820992bd4ea86e73ba228bb13dd2b0" +checksum = "cd2b7e3e27aeb0524204e58042f6e4531a720745d1b1a3978d3a084f1885f63d" dependencies = [ "amplify", "strict_encoding", @@ -2024,49 +2124,59 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[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.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.101", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2074,33 +2184,34 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.101", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-bindgen-test" -version = "0.3.45" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d381749acb0943d357dcbd8f0b100640679883fcdeeef04def49daf8d33a5426" +checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" dependencies = [ - "console_error_panic_hook", "js-sys", "minicov", - "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test-macro", @@ -2108,20 +2219,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.45" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0" +checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.101", ] [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -2135,9 +2246,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.6" +version = "0.26.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +checksum = "37493cadf42a2a939ed404698ded7fb378bf301b5011f973361779a3a74f8c93" dependencies = [ "rustls-pki-types", ] @@ -2187,53 +2298,79 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "windows-implement" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ - "windows-targets 0.48.5", + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] -name = "windows-sys" -version = "0.52.0" +name = "windows-interface" +version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" dependencies = [ - "windows-targets 0.52.6", + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", ] [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[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", ] [[package]] @@ -2242,46 +2379,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -2294,48 +2413,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -2344,32 +2439,40 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.20" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "9e27d6ad3dac991091e4d35de9ba2d2d00647c5d0fc26c5496dee55984ae111b" 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 = "zerocopy" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.101", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c5befe3e..f2acec1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,30 +10,28 @@ default-members = [ ] [workspace.package] -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" keywords = ["bitcoin", "lightning", "rgb", "smart-contracts", "lnp-bp"] categories = ["cryptography::cryptocurrencies"] authors = ["Dr Maxim Orlovsky "] homepage = "https://rgb.tech" repository = "https://github.com/RGB-WG/rgb" -rust-version = "1.77.0" +rust-version = "1.81.0" edition = "2021" license = "Apache-2.0" [workspace.dependencies] -amplify = "4.7.0" +amplify = "4.8.0" nonasync = { version = "0.1.2", features = ["log"] } -baid64 = "0.2.2" -strict_encoding = "2.7.0" -strict_types = "2.7.2" -commit_verify = "0.11.0-beta.9" -bp-core = "0.11.1-alpha.1" -bp-std = { version = "0.11.1-alpha.1", features = ["client-side-validation"] } -bp-electrum = "0.11.1-alpha.1" -bp-esplora = { version = "0.11.1-alpha.1", default-features = false } -bp-wallet = { version = "0.11.1-alpha.1" } -rgb-std = { version = "0.11.1-alpha.1" } -rgb-psbt = { version = "0.11.1-alpha.1", path = "psbt" } +baid64 = "0.4.1" +strict_encoding = "2.8.2" +strict_types = "2.8.3" +commit_verify = "0.11.1-alpha.2" +bp-core = "0.11.1-alpha.2" +bp-std = { version = "0.11.1-alpha.2", features = ["client-side-validation"] } +bp-wallet = { version = "0.11.1-alpha.2" } +rgb-std = { version = "0.11.1-alpha.2" } +rgb-psbt = { version = "0.11.1-alpha.2", path = "psbt" } indexmap = "2.4.0" chrono = "0.4.38" serde_crate = { package = "serde", version = "1", features = ["derive"] } @@ -62,12 +60,10 @@ crate-type = ["cdylib", "rlib"] amplify = { workspace = true } nonasync = { workspace = true } baid64 = { workspace = true } -bp-electrum = { workspace = true, optional = true } commit_verify = { workspace = true } strict_types = { workspace = true } bp-core = { workspace = true } bp-std = { workspace = true } -bp-esplora = { workspace = true, optional = true } bp-wallet = { workspace = true } rgb-std = { workspace = true } rgb-psbt = { workspace = true } @@ -79,8 +75,8 @@ log = { workspace = true, optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2" -rand = { version = "0.8.4", optional = true } -getrandom = { version = "0.2", features = ["js"] } +rand = { version = "0.9.1", optional = true } +getrandom = { version = "0.3", features = ["wasm_js"] } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3" @@ -89,12 +85,12 @@ wasm-bindgen-test = "0.3" default = [] all = ["esplora_blocking", "electrum_blocking", "mempool_blocking", "serde", "log", "fs", "cli"] fs = ["serde", "bp-wallet/fs", "rgb-std/fs"] -cli = ["fs", "bp-wallet/cli"] -esplora_blocking = ["bp-esplora", "bp-esplora/blocking", "bp-esplora/blocking-https"] -esplora_blocking-wasm = ["bp-esplora", "bp-esplora/blocking-wasm"] -electrum_blocking = ["bp-electrum"] -mempool_blocking = ["esplora_blocking"] -serde = ["serde_crate", "serde_yaml", "bp-std/serde", "rgb-psbt/serde"] +cli = ["fs", "bp-wallet/cli", "serde_yaml"] +esplora_blocking = ["rgb-std/esplora_blocking"] +esplora_blocking-wasm = ["rgb-std/esplora_blocking-wasm"] +electrum_blocking = ["rgb-std/electrum_blocking"] +mempool_blocking = ["rgb-std/mempool_blocking"] +serde = ["serde_crate", "bp-std/serde", "rgb-psbt/serde"] [package.metadata.docs.rs] features = ["all"] diff --git a/Dockerfile b/Dockerfile index 43d7119f..7f2ea755 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ ARG SRC_DIR=/usr/local/src/rgb ARG BUILDER_DIR=/srv/rgb # Base image -FROM rust:1.77.0-slim-bookworm as chef +FROM rust:1.81.0-slim-bookworm as chef ARG SRC_DIR ARG BUILDER_DIR diff --git a/MANIFEST.yml b/MANIFEST.yml index 5258264c..0c3ddf3b 100644 --- a/MANIFEST.yml +++ b/MANIFEST.yml @@ -3,7 +3,7 @@ Type: Binary Kind: Free software License: Apache-2.0 Language: Rust -Compiler: 1.77 +Compiler: 1.81 Author: Maxim Orlovsky Maintained: LNP/BP Standards Association, Switzerland Maintainers: diff --git a/cli/Cargo.toml b/cli/Cargo.toml index f5b9a8cd..31a3b3c7 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -24,7 +24,7 @@ commit_verify = { workspace = true } bp-std = { workspace = true, features = ["serde"] } bp-wallet = { workspace = true, features = ["cli"] } rgb-std = { workspace = true, features = ["serde"] } -rgb-runtime = { version = "0.11.1-alpha.1", path = "..", features = ["electrum_blocking", "esplora_blocking", "mempool_blocking", "log", "serde", "fs", "cli"] } +rgb-runtime = { version = "0.11.1-alpha.2", path = "..", features = ["electrum_blocking", "esplora_blocking", "mempool_blocking", "log", "serde", "fs", "cli"] } log = { workspace = true } env_logger = "0.11.5" clap = { version = "4.5.17", features = ["derive", "env"] } diff --git a/cli/README.md b/cli/README.md index 64b37475..30955721 100644 --- a/cli/README.md +++ b/cli/README.md @@ -15,22 +15,6 @@ contract), while the **ownable state** is associated with specific single-use se structures like braces, brackets, and question marks to denote sets or arrays of data types involved in state operations and their optionality. -The **state extension** allows the public to participate in specific logical parts of the contract, such as declaring a -Burn. State extension operations allow anyone to create state extensions without on-chain commitments, similar to -Bitcoin transactions not yet packaged into a block. - -### Interface - -In RGB, contract interfaces are similar to Ethereum’s ERC standards. Generic interfaces are called “RGBxx” and are -defined as independent LNP/BP standards. - -**Interface Definition**: Defines global states (like Ticker and Name) and ownable states (like Inflation and Asset), -along with operations (like Issue and Transfer). - -**Interface Implementation**: When implementing an interface, states and operations of a specific schema are bound to -the interface. For example, the FungibleToken interface implements global and ownable state bindings for the -DecentralizedIdentity schema. - ## Install from source @@ -75,55 +59,93 @@ Command-line wallet for RGB smart contracts on Bitcoin Usage: rgb [OPTIONS] Commands: - list List known wallets - default Get or set default wallet - create Create a wallet - address Generate a new wallet address(es) - taprets - schemata Prints out list of known RGB schemata - interfaces Prints out list of known RGB interfaces - contracts Prints out list of known RGB contracts - import Imports RGB data into the stash: contracts, schema, interfaces, etc - export Exports existing RGB contract - armor Convert binary RGB file into a text armored version - state Reports information about state of a contract - history-fungible Print operation history for a default fungible token under a given interface - utxos Display all known UTXOs belonging to this wallet - issue Issues new contract - invoice Create new invoice - prepare Prepare PSBT file for transferring RGB assets. In the most of cases you need to use `transfer` command instead of `prepare` and `consign` - consign Prepare consignment for transferring RGB assets. In the most of cases you need to use `transfer` command instead of `prepare` and `consign` - transfer Transfer RGB assets - inspect Inspects any RGB data file - dump Debug-dump all stash and inventory data - validate Validate transfer consignment - accept Validate transfer consignment & accept to the stash - help Print this message or the help of the given subcommand(s) + list List known named wallets + default Get or set default wallet + create Create a named wallet + address Generate a new wallet address(es) + finalize Finalize a PSBT, optionally extracting and publishing the signed transaction + extract Extract a signed transaction from PSBT. The PSBT file itself is not modified + taprets List known tapret tweaks for a wallet + schemata Prints out list of known RGB schemata + contracts Prints out list of known RGB contracts + import Imports RGB data into the stash: contracts, schema, etc + export Exports existing RGB contract + armor Convert binary RGB file into a text armored version + state Reports information about state of a contract + history Print operation history for a contract + utxos Display all known UTXOs belonging to this wallet + issue Issues new contract + invoice Create new invoice + prepare Prepare PSBT file for transferring RGB assets + consign Prepare consignment for transferring RGB assets + transfer Transfer RGB assets + inspect Inspects any RGB data file + dump Debug-dump all stash and inventory data + validate Validate transfer consignment + accept Validate transfer consignment & accept to the stash + help Print this message or the help of the given subcommand(s) Options: -v, --verbose... - Set verbosity level + Set verbosity level. + + Can be used multiple times to increase verbosity. + -w, --wallet + Use specific named wallet -W, --wallet-path - Path to wallet directory + Use wallet from a given path + --tapret-key-only Use tapret(KEY) descriptor as wallet + --wpkh Use wpkh(KEY) descriptor as wallet - -e, --esplora - Esplora server to use [env: ESPLORA_SERVER=] [default: ] + + --electrum[=] + Electrum server to use + + [env: ELECRTUM_SERVER=] + + --esplora[=] + Esplora server to use + + [env: ESPLORA_SERVER=] + + --mempool[=] + Mempool server to use + + [env: MEMPOOL_SERVER=] + --sync + Force-sync wallet data with the indexer before performing the operation -d, --data-dir - Data directory path [env: LNPBP_DATA_DIR=] [default: ~/.lnp-bp] + Data directory path + + Path to the directory that contains RGB stored data. + + [env: LNPBP_DATA_DIR=] + [default: ~/.lnp-bp] + -n, --network - Network to use [env: LNPBP_NETWORK=] [default: testnet] + Network to use + + [env: LNPBP_NETWORK=] + [default: testnet3] + + --no-network-prefix + Do not add network prefix to the `--data-dir` + + -H, --from-height + Specify blockchain height starting from which witness transactions should be checked for re-orgs + -h, --help - Print help (see more with '--help') + Print help (see a summary with '-h') + -V, --version Print version - ``` ## Preparation @@ -140,13 +162,13 @@ Here is an example descriptor: ``` ``` -$ rgb create my_wallet --wpkh "[1f09c6b9/86h/1h/0h]tpubDCrfSMscBA93FWm8qounj6kcBjnw6LxmVeKSi6VoYS327VCpoLHARWjdqeVtDt2ujDRznB9m1uXpHkDpDXyXM5gsvg2bMMmFcSHrtWUA4Py/<0;1;9;10>/*" +$ rgb --esplora=https://blockstream.info/testnet/api/ create my_wallet --wpkh "[1f09c6b9/86h/1h/0h]tpubDCrfSMscBA93FWm8qounj6kcBjnw6LxmVeKSi6VoYS327VCpoLHARWjdqeVtDt2ujDRznB9m1uXpHkDpDXyXM5gsvg2bMMmFcSHrtWUA4Py/<0;1;9;10>/*" ``` Now we can find the related files created in the wallet runtime directory: ```shell -$ ls ~/.lnp-bp/testnet3/my_wallet +$ ls ~/.lnp-bp/testnet3/my_wallet cache.yaml data.toml descriptor.toml ``` @@ -163,7 +185,7 @@ Example output: ```shell Known wallets: -my_wallet +my_wallet wpkh([1f09c6b9/86h/1h/0h]tpubDCrfSMscBA93FWm8qounj6kcBjnw6LxmVeKSi6VoYS327VCpoLHARWjdqeVtDt2ujDRznB9m1uXpHkDpDXyXM5gsvg2bMMmFcSHrtWUA4Py/<0;1;9;10>/*) ``` ### Set default wallet @@ -200,34 +222,7 @@ $ rgb schemata Example Output: ```shell -urn:lnp-bp:sc:9ZKGvK-tGs6nJvr-HQVRDDyV-zPnJYE5U-J2mb6yDi-PgBrby#frog-order-costume -``` - -### Import interface - -Now we need to import the interface definition and interface implementation, otherwise you may encounter an error: - -```shell -Error: no known interface implementation for XXX -``` - -Execute: - -```shell -$ rgb import ../rgb-schemata/interfaces/RGB20.rgb -$ rgb import ../rgb-schemata/schemata/NonInflatableAssets-RGB20.rgb -``` - -### List interface - -```shell -$ rgb interfaces -``` - -```shell -RGB21 urn:lnp-bp:if:KtMq1E-bFRhMzn5-sc9NezhQ-kn2JzeJn-VxjDCqru-sieYa#portal-ecology-hostel -RGB25 urn:lnp-bp:if:75swax-yN5mDaKB-B3peGeLu-tLctU3Ef-rAjFySp7-RMLTVF#cable-kayak-david -RGB20 urn:lnp-bp:if:9UMsvx-HkLVK5VT-GkSy7yNU-ihAUBo7a-hxQvLCFq-U4aouK#object-spring-silk +NonInflatableAsset rgb:sch:tq4jbmu9hL6kJ5galPSMBH37K1g6MqPlxTa8$!0jhZs#marble-simon-avalon 2024-04-17 ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w ``` ### Issue a contract @@ -235,8 +230,7 @@ RGB20 urn:lnp-bp:if:9UMsvx-HkLVK5VT-GkSy7yNU-ihAUBo7a-hxQvLCFq-U4aouK#object-spr Usage: ``` -$ rgb issue [OPTIONS] - +$ rgb issue ``` Tutorial: @@ -244,7 +238,7 @@ Tutorial: Write a contract declaration. (YAML in this example) ```yaml -interface: RGB20 +schema: tq4jbmu9hL6kJ5galPSMBH37K1g6MqPlxTa8$!0jhZs#marble-simon-avalon globals: spec: @@ -252,7 +246,7 @@ globals: ticker: DBG name: Debug asset details: "Pay attention: the asset has no value" - precision: 2 + precision: 2 data: terms: > SUBJECT TO, AND WITHOUT IN ANY WAY LIMITING, THE REPRESENTATIONS AND WARRANTIES OF ANY SELLER @@ -270,7 +264,6 @@ globals: PROPERTY IS BEING SOLD “AS IS”. media: ~ issuedSupply: 100000000 - created: 1687969158 assignments: assetOwner: @@ -280,14 +273,13 @@ assignments: ``` Here, we observe a seal value in the form of `txid:vout`. This hash, in -reality, represents the txid of the previously created PSBT. And `txid:vout` is +reality, represents the TXID of the previously created PSBT. And `txid:vout` is the outpoint of a valid UTXO. Compile the contract: ``` -$ rgb issue urn:lnp-bp:sc:9ZKGvK-tGs6nJvr-HQVRDDyV-zPnJYE5U-J2mb6yDi-PgBrby#frog-order-costume ./examples/rgb20-demo.yaml - +$ rgb issue issuerName ./examples/nia-demo.yaml ``` A contract (which also serves as a consignment) will be generated and imported into the current runtime's stock. @@ -295,7 +287,7 @@ A contract (which also serves as a consignment) will be generated and imported i Output: ```shell -A new contract rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB is issued and added to the stash. +A new contract rgb:hcRzR8wK-zh$jdpc-Rhsg!uH-WQ!zuV9-h7x877N-BQNcwNM is issued and added to the stash. ``` ### Export contract @@ -303,17 +295,12 @@ A new contract rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB is iss Next, we export the contract that was just created. ```shell -$ rgb export rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB -RGB: command-line wallet for RGB smart contracts - by LNP/BP Standards Association - -Loading descriptor from wallet my_wallet ... success -Loading stock ... success +$ rgb export 'rgb:hcRzR8wK-zh$jdpc-Rhsg!uH-WQ!zuV9-h7x877N-BQNcwNM' -----BEGIN RGB CONSIGNMENT----- Id: urn:lnp-bp:consignment:Ctc1wq-Xrqm78uM-nNaDsoHj-TJESKydn-4GLgtYmr-G9AdQE#smoke-oxford-burger Version: v2 Type: contract -Contract-Id: rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB +Contract-Id: rgb:hcRzR8wK-zh$jdpc-Rhsg!uH-WQ!zuV9-h7x877N-BQNcwNM Checksum-SHA256: 50468d33da7aab15c8c2b467126b721c4c3c6cf31d00c8964fb12e23fbc64777 0ssM^4-D2iQYiE=(kro^uy=TL1t60DmODi%$$wo#Ma @@ -327,9 +314,9 @@ The consignment encoded in base64 format will be output to the `stdout`. Alternatively, you can specify a file name to obtain the binary consignment: ```shell -$ rgb export rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB demo.rgb +$ rgb export 'rgb:hcRzR8wK-zh$jdpc-Rhsg!uH-WQ!zuV9-h7x877N-BQNcwNM' demo.rgb -Contract rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB exported to 'demo.rgb' +Contract rgb:hcRzR8wK-zh$jdpc-Rhsg!uH-WQ!zuV9-h7x877N-BQNcwNM exported to 'demo.rgb' ``` ### Import contract (or other kind of consignment) @@ -338,23 +325,23 @@ Consignments can be imported using the import subcommand, but the RGB CLI alread there is no need to execute it. ```shell -$ rgb import demo.rgb +$ rgb --esplora=https://blockstream.info/testnet/api/ import demo.rgb ``` ### Read the contract state ```shell -$ rgb state rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB RGB20 +$ rgb state 'rgb:hcRzR8wK-zh$jdpc-Rhsg!uH-WQ!zuV9-h7x877N-BQNcwNM' Global: - spec := (naming=(ticker=("DBG"), name=("Debug asset"), details=1(("Pay attention: the asset has no value"))), precision=2) - data := (terms=("..."), media=~) - issuedSupply := (100000000) - created := (1687969158) + spec := ticker "DEMO", name "Demo asset", details "Pay attention: the asset has no value".some, precision centi + terms := text "SUBJECT TO, AND WITHOUT IN ANY WAY LIMITING, THE REPRESENTATIONS AND WARRANTIES OF ANY SELLER EXPRESSLY SET FORTH IN THIS AGREEMENT OR ANY OTHER EXPRESS OBLIGATION OF SELLERS PURSUANT TO THE TERMS HEREOF, AND ACKNOWLEDGING THE PRIOR USE OF THE PROPERTY AND PURCHASER’S OPPORTUNITY TO INSPECT THE PROPERTY, PURCHASER AGREES TO PURCHASE THE PROPERTY “AS IS”, “WHERE IS”, WITH ALL FAULTS AND CONDITIONS THEREON. ANY WRITTEN OR ORAL INFORMATION, REPORTS, STATEMENTS, DOCUMENTS OR RECORDS CONCERNING THE PROPERTY PROVIDED OR MADE AVAILABLE TO PURCHASER, ITS AGENTS OR CONSTITUENTS BY ANY SELLER, ANY SELLER’S AGENTS, EMPLOYEES OR THIRD PARTIES REPRESENTING OR PURPORTING TO REPRESENT ANY SELLER, SHALL NOT BE REPRESENTATIONS OR WARRANTIES, UNLESS SPECIFICALLY SET FORTH HEREIN. IN PURCHASING THE PROPERTY OR TAKING OTHER ACTION HEREUNDER, PURCHASER HAS NOT AND SHALL NOT RELY ON ANY SUCH DISCLOSURES, BUT RATHER, PURCHASER SHALL RELY ONLY ON PURCHASER’S OWN INSPECTION OF THE PROPERTY AND THE REPRESENTATIONS AND WARRANTIES HEREIN. PURCHASER ACKNOWLEDGES THAT THE PURCHASE PRICE REFLECTS AND TAKES INTO ACCOUNT THAT THE PROPERTY IS BEING SOLD “AS IS”. +", media ~ + issuedSupply := 100000000 Owned: + State Seal Witness assetOwner: - ``` ### List contract @@ -368,7 +355,8 @@ $ rgb contracts Example output: ```shell -rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB +rgb:hcRzR8wK-zh$jdpc-Rhsg!uH-WQ!zuV9-h7x877N-BQNcwNM BitcoinTestnet3 2025-03-08 rgb:sch:tq4jbmu9hL6kJ5galPSMBH37K1g6MqPlxTa8$!0jhZs#marble-simon-avalon + Developer: issuerName ``` ### Take an address @@ -376,7 +364,7 @@ rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB ```shell $ rgb address Term. Address -&0/0 tb1qeyu926l47099vtp7wewvhwt03vc5sn5c6t604p +&0/1 tb1qeyu926l47099vtp7wewvhwt03vc5sn5c6t604p ``` Run multiple times to generate more addresses at different indexes. To view an address at given index, for example `0`, @@ -384,29 +372,22 @@ execute: ```shell $ rgb address --index 0 +Term. Address +&0/0 tb1qeyu926l47099vtp7wewvhwt03vc5sn5c6t604p ``` ### Create an address based invoice ```shell -$ rgb invoice --address-based rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB RGB20 100 - +$ rgb invoice --address-based 'rgb:hcRzR8wK-zh$jdpc-Rhsg!uH-WQ!zuV9-h7x877N-BQNcwNM' --amount 100 ``` Created invoice: ```shell -rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB/RGB20/100+tb:q0q6u0urtzn59cg9qacm7c5aq7ud3wmgms7stew +rgb:hcRzR8wK-zh$jdpc-Rhsg!uH-WQ!zuV9-h7x877N-BQNcwNM/~/BF+tb3:wvout:A3g1x$Br-FOhcIKD-uN!xToP-cbF20bA-AAAAAAA-AAAAAAA-AIi0trA ``` -Here's a breakdown of the different parts of the invoice string: - -1. `rgb:DF4vyV9-i85ZzUqbq-QLxvKtgtp-AJk9NvpL3-k4AHmcRrf-vyHksB`: This is the contract ID, which is a unique identifier - for the contract associated with this invoice. -2. `RGB20`: This is the interface (or protocol) used for the transaction. -3. `100`: This is the amount of the transaction, which is 100 units. -4. `tb:q0q6u0urtzn59cg9qacm7c5aq7ud3wmgms7stew`: This is the beneficiary of the transaction - The invoice string could also includes some additional parameters that are encoded as query parameters, which are separated by the `?` character. These parameters are used to provide additional information about the transaction, such as the operation being performed or the assignment associated with the transaction. @@ -414,7 +395,7 @@ as the operation being performed or the assignment associated with the transacti ### Validate the consignment ```shell -$ rgb validate demo.rgb +$ rgb --esplora=https://blockstream.info/testnet/api/ validate demo.rgb ``` Example output: @@ -432,10 +413,10 @@ Validation warnings: Create transfer: ```shell -$ rgb transfer [PSBT] -$ rgb transfer \ - rgb:2bLwMXo-deVgzKq97-GUVy6wXea-G1nE84nxw-v5CX3WSJN-mbhsMn7/RGB20/1000+bcrt:p9yjaffzhuh9p7d9gnwfunxssngesk25tz7rudu4v69dl6e7w7qhq5x43k5 \ - transfer.consignment \ +$ rgb transfer [PSBT] +$ rgb transfer \ + rgb:hcRzR8wK-zh$jdpc-Rhsg!uH-WQ!zuV9-h7x877N-BQNcwNM/~/BF+tb3:wvout:A3g1x$Br-FOhcIKD-uN!xToP-cbF20bA-AAAAAAA-AAAAAAA-AIi0trA \ + transfer.consignment \ alice.psbt ``` @@ -446,5 +427,5 @@ Now you can use bdk-cli or any other wallet to sign and broadcast the transactio As receiver: ```shell -$ rgb accept -f CONSIGNMENT_FILE +$ rgb accept -f ``` diff --git a/cli/src/args.rs b/cli/src/args.rs index b0477292..224cfcf4 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -30,8 +30,9 @@ use bpstd::{Network, Wpkh, XpubDerivable}; use bpwallet::cli::{Args as BpArgs, Config, DescriptorOpts}; use bpwallet::Wallet; use rgb::persistence::Stock; -use rgb::resolvers::AnyResolver; +use rgb::validation::ResolveWitness; use rgb::{ChainNet, RgbDescr, RgbWallet, TapretKey, WalletError}; +use rgbstd::indexers::AnyResolver; use rgbstd::persistence::fs::FsBinStore; use strict_types::encoding::{DecodeError, DeserializeError}; @@ -189,7 +190,9 @@ impl RgbArgs { --esplora --mempool or --electrum argument")), } .map_err(WalletError::Resolver)?; - resolver.check_chain_net(self.chain_net())?; + resolver + .check_chain_net(self.chain_net()) + .map_err(|e| WalletError::Resolver(e.to_string()))?; Ok(resolver) } diff --git a/cli/src/command.rs b/cli/src/command.rs index 65048285..b897e33e 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -21,11 +21,10 @@ use std::fs; use std::fs::File; -use std::ops::ControlFlow; use std::path::PathBuf; use std::str::FromStr; -use amplify::confinement::{SmallOrdMap, TinyOrdMap, TinyOrdSet, U16 as MAX16}; +use amplify::confinement::{SmallOrdMap, U16 as MAX16}; use baid64::DisplayBaid64; use bpstd::psbt::{Psbt, PsbtVer}; use bpstd::seals::SecretSeal; @@ -33,10 +32,8 @@ use bpstd::{Sats, Txid, XpubDerivable}; use bpwallet::cli::{BpCommand, Config, Exec}; use bpwallet::Wallet; use rgb::containers::{ - BuilderSeal, ConsignmentExt, ContainerVer, ContentId, ContentSigs, Contract, FileContent, - Supplement, Transfer, UniversalFile, + BuilderSeal, ConsignmentExt, ContainerVer, Contract, FileContent, Transfer, UniversalFile, }; -use rgb::interface::{AssignmentsFilter, ContractOp, IfaceId}; use rgb::invoice::{Beneficiary, Pay2Vout, RgbInvoice, RgbInvoiceBuilder, XChainNet}; use rgb::persistence::{MemContract, StashReadProvider, Stock}; use rgb::resolvers::ContractIssueResolver; @@ -48,13 +45,11 @@ use rgb::{ OwnedFraction, RgbDescr, RgbKeychain, RgbWallet, StateType, TokenIndex, TransferParams, WalletError, WalletProvider, }; -use rgbstd::interface::{AllocatedState, ContractIface, OwnedIface}; -use rgbstd::persistence::{MemContractState, StockError}; -use rgbstd::stl::rgb_contract_stl; +use rgbstd::contract::{AllocatedState, AssignmentsFilter, ContractData, ContractOp}; +use rgbstd::persistence::MemContractState; use rgbstd::{KnownState, OutputAssignment}; use serde_crate::{Deserialize, Serialize}; -use strict_types::encoding::{FieldName, TypeName}; -use strict_types::StrictVal; +use strict_types::{FieldName, StrictVal}; use crate::RgbArgs; @@ -72,14 +67,12 @@ pub enum Command { /// Prints out list of known RGB schemata Schemata, - /// Prints out list of known RGB interfaces - Interfaces, /// Prints out list of known RGB contracts #[display("contracts")] Contracts, - /// Imports RGB data into the stash: contracts, schema, interfaces, etc + /// Imports RGB data into the stash: contracts, schema, etc #[display("import")] Import { /// Use BASE64 ASCII armoring for binary data @@ -100,7 +93,7 @@ pub enum Command { armored: bool, /// Contract to export - contract: ContractId, + contract_id: ContractId, /// File with RGB data /// @@ -126,13 +119,9 @@ pub enum Command { /// Contract identifier contract_id: ContractId, - - /// Interface to interpret the state data - iface: Option, }, - /// Print operation history for a default fungible token under a given - /// interface + /// Print operation history for a contract #[display("history")] History { /// Print detailed information @@ -141,9 +130,6 @@ pub enum Command { /// Contract identifier contract_id: ContractId, - - /// Interface to interpret the state data - iface: Option, }, /// Display all known UTXOs belonging to this wallet @@ -152,14 +138,11 @@ pub enum Command { /// Issues new contract #[display("issue")] Issue { - /// Schema name to use for the contract - schema: SchemaId, //String, - /// Issuer identity string issuer: Identity, /// File containing contract genesis description in YAML format - contract: PathBuf, + contract_path: PathBuf, }, /// Create new invoice @@ -169,22 +152,11 @@ pub enum Command { #[arg(short, long)] address_based: bool, - /// Interface to interpret the state data - #[arg(short, long)] - iface: Option, - - /// Operation to use for the invoice + /// Assignment state name to use for the invoice /// - /// If no operation is provided, the interface default operation is used. + /// If no state name is provided, it will be detected. #[arg(short, long)] - operation: Option, - - /// State name to use for the invoice - /// - /// If no state name is provided, the interface default state name for the operation is - /// used. - #[arg(short, long, requires = "operation")] - state: Option, + assignment_name: Option, /// Contract identifier contract_id: ContractId, @@ -362,12 +334,6 @@ impl Exec for RgbArgs { print!("{info}"); } } - Command::Interfaces => { - let stock = self.rgb_stock()?; - for info in stock.ifaces()? { - print!("{info}"); - } - } Command::Contracts => { let stock = self.rgb_stock()?; for info in stock.contracts()? { @@ -377,16 +343,10 @@ impl Exec for RgbArgs { Command::History { contract_id, - iface, details, } => { let wallet = self.rgb_wallet(&config)?; - let iface = match contract_default_iface_name(*contract_id, wallet.stock(), iface)? - { - ControlFlow::Continue(name) => name, - ControlFlow::Break(_) => return Ok(()), - }; - let mut history = wallet.history(*contract_id, iface)?; + let mut history = wallet.history(*contract_id)?; 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"); @@ -404,7 +364,7 @@ impl Exec for RgbArgs { { print!("{:9}\t", direction.to_string()); if let AllocatedState::Amount(amount) = state { - print!("{: >9}", amount.value()); + print!("{: >9}", amount.as_u64()); } else { print!("{state:>9}"); } @@ -440,29 +400,12 @@ impl Exec for RgbArgs { UniversalFile::Kit(kit) => { let id = kit.kit_id(); eprintln!("Importing kit {id}:"); - let mut iface_names = map![]; let mut schema_names = map![]; - for iface in &kit.ifaces { - let iface_id = iface.iface_id(); - iface_names.insert(iface_id, &iface.name); - eprintln!("- interface {} {:-}", iface.name, iface_id); - } for schema in &kit.schemata { let schema_id = schema.schema_id(); schema_names.insert(schema_id, &schema.name); eprintln!("- schema {} {:-}", schema.name, schema_id); } - for iimpl in &kit.iimpls { - let iface = iface_names - .get(&iimpl.iface_id) - .map(|name| name.to_string()) - .unwrap_or_else(|| iimpl.iface_id.to_string()); - let schema = schema_names - .get(&iimpl.schema_id) - .map(|name| name.to_string()) - .unwrap_or_else(|| iimpl.schema_id.to_string()); - eprintln!("- implementation of {iface} for {schema}",); - } for lib in &kit.scripts { eprintln!("- script library {}", lib.id()); } @@ -476,12 +419,12 @@ impl Exec for RgbArgs { eprintln!("Importing consignment {id}:"); let resolver = self.resolver()?; eprint!("- validating the contract {} ... ", contract.contract_id()); - let contract = contract.validate(&resolver, self.chain_net()).map_err( - |(status, _)| { + let contract = contract + .validate(&resolver, self.chain_net(), None) + .map_err(|(status, _)| { eprintln!("failure"); status.to_string() - }, - )?; + })?; eprintln!("success"); stock.import_contract(contract, &resolver)?; eprintln!("Consignment is imported"); @@ -495,17 +438,17 @@ impl Exec for RgbArgs { } Command::Export { armored: _, - contract, + contract_id, file, } => { let stock = self.rgb_stock()?; let contract = stock - .export_contract(*contract) + .export_contract(*contract_id) .map_err(|err| err.to_string())?; if let Some(file) = file { // TODO: handle armored flag contract.save_file(file)?; - eprintln!("Contract {contract} exported to '{}'", file.display()); + eprintln!("Contract {contract_id} exported to '{}'", file.display()); } else { println!("{contract}"); } @@ -516,11 +459,7 @@ impl Exec for RgbArgs { println!("{content}"); } - Command::State { - contract_id, - iface, - all, - } => { + Command::State { contract_id, all } => { let stock_path = self.general.base_dir(); let stock = self.load_stock(stock_path)?; @@ -537,11 +476,6 @@ impl Exec for RgbArgs { } } - let iface = match contract_default_iface_name(*contract_id, &stock, iface)? { - ControlFlow::Continue(name) => name, - ControlFlow::Break(_) => return Ok(()), - }; - let stock_wallet = match self.rgb_wallet_from_stock(&config, stock) { Ok(wallet) => StockOrWallet::Wallet(wallet), Err((stock, _)) => StockOrWallet::Stock(stock), @@ -556,16 +490,13 @@ impl Exec for RgbArgs { } }; - let contract = stock_wallet - .stock() - .contract_iface(*contract_id, tn!(iface.to_owned()))?; + let contract = stock_wallet.stock().contract_data(*contract_id)?; println!("\nGlobal:"); - for global in &contract.iface.global_state { - if let Ok(values) = contract.global(global.name.clone()) { - for val in values { - println!(" {} := {}", global.name, val); - } + for global_details in contract.schema.global_types.values() { + let values = contract.global(global_details.name.clone()); + for val in values { + println!(" {} := {}", global_details.name, val); } } @@ -607,7 +538,7 @@ impl Exec for RgbArgs { println!("\nOwned:"); fn witness( allocation: &OutputAssignment, - contract: &ContractIface>, + contract: &ContractData>, ) -> String { allocation .witness @@ -615,10 +546,10 @@ impl Exec for RgbArgs { .map(|info| format!("{} ({})", info.id, info.ord)) .unwrap_or_else(|| s!("~")) } - for owned in &contract.iface.assignments { + for details in contract.schema.owned_types.values() { println!(" State \t{:78}\tWitness", "Seal"); - println!(" {}:", owned.name); - if let Ok(allocations) = contract.fungible(owned.name.clone(), &filter) { + println!(" {}:", details.name); + if let Ok(allocations) = contract.fungible(details.name.clone(), &filter) { for allocation in allocations { println!( " {: >9}\t{}\t{} {}", @@ -629,7 +560,7 @@ impl Exec for RgbArgs { ); } } - if let Ok(allocations) = contract.data(owned.name.clone(), &filter) { + if let Ok(allocations) = contract.data(details.name.clone(), &filter) { for allocation in allocations { println!( " {: >9}\t{}\t{} {}", @@ -640,18 +571,7 @@ impl Exec for RgbArgs { ); } } - 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) { + if let Ok(allocations) = contract.rights(details.name.clone(), &filter) { for allocation in allocations { println!( " {: >9}\t{}\t{} {}", @@ -665,13 +585,12 @@ impl Exec for RgbArgs { } } Command::Issue { - schema: schema_id, issuer, - contract, + contract_path, } => { let mut stock = self.rgb_stock()?; - let file = fs::File::open(contract)?; + let file = fs::File::open(contract_path)?; let code = serde_yaml::from_reader::<_, serde_yaml::Value>(file)?; @@ -679,35 +598,18 @@ impl Exec for RgbArgs { .as_mapping() .expect("invalid YAML root-level structure"); - let iface_name = code - .get("interface") - .expect("contract must specify interface under which it is constructed") + let schema_id_str = code + .get("schema") + .expect("must specify a schema") .as_str() - .expect("interface name must be a string"); - let schema_ifaces = stock.schema(*schema_id)?; - let iface_name = tn!(iface_name.to_owned()); - let iface = stock - .iface(iface_name.clone()) - .or_else(|_| { - let id = IfaceId::from_str(iface_name.as_str())?; - stock.iface(id).map_err(WalletError::from) - })? - .clone(); - let iface_id = iface.iface_id(); - let iface_impl = schema_ifaces.get(iface_id).ok_or_else(|| { - WalletError::Custom(format!( - "no known interface implementation for {iface_name}" - )) - })?; - - let mut builder = stock.contract_builder( - issuer.clone(), - *schema_id, - iface_id, - self.chain_net(), - )?; - let types = builder.type_system().clone(); + .expect("schema must be a string"); + + let schema_id = SchemaId::from_str(schema_id_str)?; + let schema = stock.schema(schema_id)?; + let mut builder = + stock.contract_builder(issuer.clone(), schema_id, self.chain_net())?; + let types = builder.type_system().clone(); if let Some(globals) = code.get("globals") { for (name, val) in globals .as_mapping() @@ -716,18 +618,10 @@ impl Exec for RgbArgs { let name = name .as_str() .expect("invalid YAML: global name must be a string"); - let state_type = iface_impl - .global_state - .iter() - .find(|info| info.name.as_str() == name) - .unwrap_or_else(|| panic!("unknown type name '{name}'")) - .id; - let sem_id = schema_ifaces - .schema - .global_types - .get(&state_type) - .expect("invalid schema implementation") - .sem_id; + // Workaround for borrow checker: + let name = FieldName::try_from(name.to_owned()).expect("invalid type name"); + let (type_id, global_details) = schema.global(name); + let sem_id = global_details.global_state_schema.sem_id; let val = StrictVal::from(val.clone()); let typed_val = types .typify(val, sem_id) @@ -737,11 +631,8 @@ impl Exec for RgbArgs { let serialized = types .strict_serialize_type::(&typed_val) .expect("internal error"); - // Workaround for borrow checker: - let field_name = - FieldName::try_from(name.to_owned()).expect("invalid type name"); builder = builder - .add_global_state(field_name, serialized) + .add_global_state_raw(*type_id, serialized) .expect("invalid global state data"); } } @@ -754,17 +645,10 @@ impl Exec for RgbArgs { let name = name .as_str() .expect("invalid YAML: assignments name must be a string"); - let state_type = iface_impl - .assignments - .iter() - .find(|info| info.name.as_str() == name) - .expect("unknown type name") - .id; - let state_schema = schema_ifaces - .schema - .owned_types - .get(&state_type) - .expect("invalid schema implementation"); + // Workaround for borrow checker: + let name = FieldName::try_from(name.to_owned()).expect("invalid type name"); + let (type_id, assignment_details) = schema.assignment(name); + let state_schema = assignment_details.owned_state_schema; let assign = val.as_mapping().expect("an assignment must be a mapping"); let seal = assign @@ -775,9 +659,6 @@ impl Exec for RgbArgs { let seal = OutputSeal::from_str(seal).expect("invalid seal definition"); let seal = GenesisSeal::new_random(seal.txid, seal.vout); - // Workaround for borrow checker: - let field_name = - FieldName::try_from(name.to_owned()).expect("invalid type name"); match state_schema.state_type() { StateType::Void => todo!(), StateType::Fungible => { @@ -788,11 +669,10 @@ impl Exec for RgbArgs { .expect("fungible state must be an integer"); let seal = BuilderSeal::Revealed(seal); builder = builder - .add_fungible_state(field_name, seal, amount) + .add_fungible_state_raw(*type_id, seal, amount) .expect("invalid global state data"); } StateType::Structured => todo!(), - StateType::Attachment => todo!(), } } } @@ -807,10 +687,8 @@ impl Exec for RgbArgs { } Command::Invoice { address_based, - operation, - state, + assignment_name, contract_id, - iface, amount, token_index, token_fraction, @@ -837,7 +715,7 @@ impl Exec for RgbArgs { .next() .expect("no addresses left") .addr; - Beneficiary::WitnessVout(Pay2Vout::new(addr.payload)) + Beneficiary::WitnessVout(Pay2Vout::new(addr.payload), None) } (_, Some(outpoint)) => { let seal = GraphSeal::new_random(outpoint.txid, outpoint.vout); @@ -846,126 +724,66 @@ impl Exec for RgbArgs { } }; - let iface = match contract_default_iface_name(*contract_id, wallet.stock(), iface)? - { - ControlFlow::Continue(name) => wallet.stock().iface(name)?, - ControlFlow::Break(_) => return Ok(()), - }; - let iface_name = &iface.name; - let Some(op_name) = operation - .clone() - .map(FieldName::try_from) - .transpose() - .map_err(|e| WalletError::Invoicing(format!("invalid operation name - {e}")))? - .or(iface.default_operation.clone()) - else { - return Err(WalletError::Invoicing(format!( - "interface {iface_name} doesn't have default operation" - ))); - }; - let Some(iface_op) = iface.transitions.get(&op_name) else { - return Err(WalletError::Invoicing(format!( - "interface {iface_name} doesn't have operation {op_name}" - ))); - }; - let state_name = state - .clone() - .map(FieldName::try_from) - .transpose() - .map_err(|e| WalletError::Invoicing(format!("invalid state name - {e}")))? - .or_else(|| iface_op.default_assignment.clone()) - .ok_or_else(|| { - WalletError::Invoicing(format!( - "interface {iface_name} doesn't have a default state for the \ - operation {op_name}" - )) - })?; - let Some(assign_iface) = iface.assignments.get(&state_name) else { - return Err(WalletError::Invoicing(format!( - "interface {iface_name} doesn't have state {state_name} in operation \ - {op_name}" - ))); - }; - let mut builder = RgbInvoiceBuilder::new(XChainNet::bitcoin(network, beneficiary)) - .set_contract(*contract_id) - .set_interface(iface_name.clone()); + .set_contract(*contract_id); - if operation.is_some() { - builder = builder.set_operation(op_name); - if let Some(state) = state { - builder = builder.set_operation(fname!(state.clone())); - } - } - - match (assign_iface.owned_state, amount, token_index.map(|i| (i, token_fraction))) { - ( - OwnedIface::Rights - | OwnedIface::Amount - | OwnedIface::AnyData - | OwnedIface::Data(_), - None, - None, - ) => { - // There is no state which has to be added to the invoice - } - (OwnedIface::Rights, Some(_), None | Some(_)) - | (OwnedIface::Rights, None, Some(_)) => { - return Err(WalletError::Invoicing(format!( - "state {state_name} in interface {iface_name} defines a right and it \ - can't has a value or a token information" - ))); - } - (OwnedIface::Amount, _, Some(_)) => { - return Err(WalletError::Invoicing(format!( - "state {state_name} in interface {iface_name} defines a fungible \ - state, while a non-fungible token index is provided for the invoice. \ - Please use only --amount argument" - ))); - } - (OwnedIface::Amount, Some(amount), None) => { + let state_type = match (amount, token_index.map(|i| (i, token_fraction))) { + (Some(amount), None) => { builder = builder.set_amount_raw(*amount); + StateType::Fungible } - (OwnedIface::Data(_) | OwnedIface::AnyData, Some(_), _) => { - return Err(WalletError::Invoicing(format!( - "state {state_name} in interface {iface_name} defines a non-fungible \ - state, while a fungible amount is provided for the invoice. Please \ - use only --token-index and --token-fraction arguments" - ))); - } - (OwnedIface::Data(sem_id), None, Some(_)) - if sem_id - != rgb_contract_stl() - .types - .get(&tn!("Allocation")) - .expect("STL is broken") - .sem_id_named(&tn!("Allocation")) => - { - return Err(WalletError::Invoicing(format!( - "state {state_name} in interface {iface_name} has a type which can't \ - be used with a non-fungible state allocation" - ))); - } - (OwnedIface::AnyData | OwnedIface::Data(_), None, Some((index, fraction))) => { + (None, Some((index, fraction))) => { builder = builder.set_allocation_raw(Allocation::with( index, fraction.unwrap_or(OwnedFraction::from(0)), - )) - } - - (OwnedIface::Any, _, _) => { - return Err(WalletError::Invoicing(format!( - "state {state_name} in interface {iface_name} can be of any type; \ - adding it to the invoice is impossible" - ))); + )); + StateType::Structured } - (OwnedIface::AnyAttach, _, _) => { + _ => { return Err(WalletError::Invoicing(s!( - "invoicing with attachments is not yet supported" - ))); + "only amount or token data should be provided" + ))) + } + }; + + let mut ass_name = assignment_name + .clone() + .map(FieldName::try_from) + .transpose() + .map_err(|e| { + WalletError::Invoicing(format!("invalid assignment name - {e}")) + })?; + + if let Ok(contract) = wallet.stock().contract_data(*contract_id) { + if let Some(ref assignment_name) = ass_name { + let (_, details) = contract.schema.assignment(assignment_name.clone()); + if details.owned_state_schema.state_type() != state_type { + return Err(WalletError::Invoicing(s!( + "invalid assignment name for state type" + ))); + } + } else { + let assignment_types = + contract.schema.assignment_types_for_state(state_type); + if assignment_types.len() == 1 { + ass_name = Some( + contract + .schema + .assignment_name(*assignment_types[0]) + .clone(), + ); + } else { + return Err(WalletError::Invoicing(s!( + "cannot detect a default assignment type" + ))); + } } } + if let Some(name) = ass_name { + builder = builder.set_assignment_name(name); + } + let invoice = builder.finish(); println!("{invoice}"); } @@ -1045,8 +863,6 @@ impl Exec for RgbArgs { version: ContainerVer, transfer: bool, terminals: SmallOrdMap, - supplements: TinyOrdSet, - signatures: TinyOrdMap, } let content = UniversalFile::load_file(file)?; @@ -1067,7 +883,6 @@ impl Exec for RgbArgs { s!("genesis.yaml") => serde_yaml::to_string(&consignment.genesis)?, s!("schema.yaml") => serde_yaml::to_string(&consignment.schema)?, s!("bundles.yaml") => serde_yaml::to_string(&consignment.bundles)?, - s!("extensions.yaml") => serde_yaml::to_string(&consignment.extensions)?, s!("types.sty") => consignment.types.to_string(), ]; for lib in consignment.scripts { @@ -1077,22 +892,10 @@ impl Exec for RgbArgs { String::from_utf8_unchecked(buf) }); } - for (iface, iimpl) in consignment.ifaces { - map.insert( - format!("iface-{}.yaml", iface.name), - serde_yaml::to_string(&iface)?, - ); - map.insert( - format!("impl-{}.yaml", iface.name), - serde_yaml::to_string(&iimpl)?, - ); - } let contract = ConsignmentInspection { version: consignment.version, transfer: consignment.transfer, terminals: consignment.terminals, - supplements: consignment.supplements, - signatures: consignment.signatures, }; map.insert(s!("consignment-meta.yaml"), serde_yaml::to_string(&contract)?); let path = path.as_ref().expect("required by clap"); @@ -1135,29 +938,17 @@ impl Exec for RgbArgs { fs::remove_dir_all(root_dir).ok(); fs::create_dir_all(format!("{root_dir}/stash/schemata"))?; - fs::create_dir_all(format!("{root_dir}/stash/ifaces"))?; fs::create_dir_all(format!("{root_dir}/stash/geneses"))?; fs::create_dir_all(format!("{root_dir}/stash/bundles"))?; fs::create_dir_all(format!("{root_dir}/stash/witnesses"))?; - fs::create_dir_all(format!("{root_dir}/stash/extensions"))?; - fs::create_dir_all(format!("{root_dir}/stash/supplements"))?; fs::create_dir_all(format!("{root_dir}/state"))?; fs::create_dir_all(format!("{root_dir}/index"))?; // Stash - for (id, schema_ifaces) in stock.as_stash_provider().debug_schemata() { - fs::write( - format!( - "{root_dir}/stash/schemata/{}.{id:-#}.yaml", - schema_ifaces.schema.name - ), - serde_yaml::to_string(&schema_ifaces)?, - )?; - } - for (id, iface) in stock.as_stash_provider().debug_ifaces() { + for (id, schema) in stock.as_stash_provider().debug_schemata() { fs::write( - format!("{root_dir}/stash/ifaces/{}.{id:-#}.yaml", iface.name), - serde_yaml::to_string(stock.iface(*id)?)?, + format!("{root_dir}/stash/schemata/{}.{id:-#}.yaml", schema.name), + serde_yaml::to_string(&schema)?, )?; } for (id, genesis) in stock.as_stash_provider().debug_geneses() { @@ -1166,17 +957,6 @@ impl Exec for RgbArgs { serde_yaml::to_string(genesis)?, )?; } - for (id, list) in stock.as_stash_provider().debug_suppl() { - for suppl in list { - fs::write( - format!( - "{root_dir}/stash/geneses/{id:-}.suppl.{}.yaml", - suppl.suppl_id() - ), - serde_yaml::to_string(suppl)?, - )?; - } - } for (id, bundle) in stock.as_stash_provider().debug_bundles() { fs::write( format!("{root_dir}/stash/bundles/{id}.yaml"), @@ -1189,23 +969,10 @@ impl Exec for RgbArgs { serde_yaml::to_string(witness)?, )?; } - for (id, extension) in stock.as_stash_provider().debug_extensions() { - fs::write( - format!("{root_dir}/stash/extensions/{id}.yaml"), - serde_yaml::to_string(extension)?, - )?; - } - for (id, suppl) in stock.as_stash_provider().debug_suppl() { - fs::write( - format!("{root_dir}/stash/supplements/{id:#}.yaml"), - serde_yaml::to_string(suppl)?, - )?; - } fs::write( format!("{root_dir}/stash/seal-secret.yaml"), serde_yaml::to_string(stock.as_stash_provider().debug_secret_seals())?, )?; - // TODO: Add sigs debugging // State fs::write( @@ -1246,7 +1013,7 @@ impl Exec for RgbArgs { let mut resolver = self.resolver()?; let consignment = Transfer::load_file(file)?; resolver.add_consignment_txes(&consignment); - let status = match consignment.validate(&resolver, self.chain_net()) { + let status = match consignment.validate(&resolver, self.chain_net(), None) { Ok(consignment) => consignment.into_validation_status(), Err((status, _)) => status, }; @@ -1263,7 +1030,7 @@ impl Exec for RgbArgs { let transfer = Transfer::load_file(file)?; resolver.add_consignment_txes(&transfer); let valid = transfer - .validate(&resolver, self.chain_net()) + .validate(&resolver, self.chain_net(), None) .map_err(|(status, _)| status)?; stock.accept_transfer(valid, &resolver)?; eprintln!("Transfer accepted into the stash"); @@ -1272,39 +1039,3 @@ impl Exec for RgbArgs { Ok(()) } } - -fn contract_default_iface_name( - contract_id: ContractId, - stock: &Stock, - iface: &Option, -) -> Result, StockError> { - if let Some(iface) = iface { - return Ok(ControlFlow::Continue(tn!(iface.clone()))); - }; - let info = stock.contract_info(contract_id)?; - let schema = stock.schema(info.schema_id)?; - Ok(match schema.iimpls.len() { - 0 => { - eprintln!("contract doesn't implement any interface and thus can't be read"); - ControlFlow::Break(()) - } - 1 => ControlFlow::Continue( - schema - .iimpls - .first_key_value() - .expect("one interface is present") - .0 - .clone(), - ), - _ => { - eprintln!( - "contract implements multiple interface, please select one of them to read the \ - contract:" - ); - for iface in schema.iimpls.keys() { - eprintln!("{iface}"); - } - ControlFlow::Break(()) - } - }) -} diff --git a/cli/src/main.rs b/cli/src/main.rs index 3d94c026..a9c01223 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -22,8 +22,6 @@ #[macro_use] extern crate amplify; #[macro_use] -extern crate strict_types; -#[macro_use] extern crate log; #[macro_use] extern crate clap; diff --git a/examples/rgb20-demo.yaml b/examples/nia-demo.yaml similarity index 95% rename from examples/rgb20-demo.yaml rename to examples/nia-demo.yaml index 475973a6..1dd931f5 100644 --- a/examples/rgb20-demo.yaml +++ b/examples/nia-demo.yaml @@ -1,4 +1,4 @@ -interface: RGB20Fixed +schema: tq4jbmu9hL6kJ5galPSMBH37K1g6MqPlxTa8$!0jhZs#marble-simon-avalon globals: spec: diff --git a/examples/rgb20-demo.con b/examples/rgb20-demo.con deleted file mode 100644 index d01c6ea2..00000000 --- a/examples/rgb20-demo.con +++ /dev/null @@ -1,33 +0,0 @@ -contract Test: NonInflatableAsset - global spec - ticker = "Demo", - name = "Demo asset" - details = "Pay attention: the asset has no value" - precision = centiMicro - - global terms - text = """ - SUBJECT TO, AND WITHOUT IN ANY WAY LIMITING, THE REPRESENTATIONS AND WARRANTIES OF ANY SELLER - EXPRESSLY SET FORTH IN THIS AGREEMENT OR ANY OTHER EXPRESS OBLIGATION OF SELLERS PURSUANT TO THE - TERMS HEREOF, AND ACKNOWLEDGING THE PRIOR USE OF THE PROPERTY AND PURCHASER’S OPPORTUNITY - TO INSPECT THE PROPERTY, PURCHASER AGREES TO PURCHASE THE PROPERTY “AS IS”, “WHERE IS”, - WITH ALL FAULTS AND CONDITIONS THEREON. ANY WRITTEN OR ORAL INFORMATION, REPORTS, STATEMENTS, - DOCUMENTS OR RECORDS CONCERNING THE PROPERTY PROVIDED OR MADE AVAILABLE TO PURCHASER, ITS AGENTS - OR CONSTITUENTS BY ANY SELLER, ANY SELLER’S AGENTS, EMPLOYEES OR THIRD PARTIES REPRESENTING OR - PURPORTING TO REPRESENT ANY SELLER, SHALL NOT BE REPRESENTATIONS OR WARRANTIES, UNLESS - SPECIFICALLY SET FORTH HEREIN. IN PURCHASING THE PROPERTY OR TAKING OTHER ACTION HEREUNDER, - PURCHASER HAS NOT AND SHALL NOT RELY ON ANY SUCH DISCLOSURES, BUT RATHER, PURCHASER SHALL RELY - ONLY ON PURCHASER’S OWN INSPECTION OF THE PROPERTY AND THE REPRESENTATIONS AND WARRANTIES - HEREIN. PURCHASER ACKNOWLEDGES THAT THE PURCHASE PRICE REFLECTS AND TAKES INTO ACCOUNT THAT THE - PROPERTY IS BEING SOLD “AS IS”. - """ - media = ~ - - global issuedSupply - 1_000_000__000_000_00 - - owned assetOwner - state = 1_000_000__000_000_00 - seal = - txid = #01d46e52c4bdb51931a0eae83e958c78bdef9cac2057b36d55370410edafdd42 - vout = 0 diff --git a/examples/rgb20-demo.rgb b/examples/rgb20-demo.rgb deleted file mode 100644 index 0e2644aa..00000000 Binary files a/examples/rgb20-demo.rgb and /dev/null differ diff --git a/examples/rgb20-demo.rgba b/examples/rgb20-demo.rgba deleted file mode 100644 index e8bd385d..00000000 --- a/examples/rgb20-demo.rgba +++ /dev/null @@ -1,120 +0,0 @@ ------BEGIN RGB CONSIGNMENT----- -Id: rgb:csg:qX!1P1VF-il9DLFx-yjcpNvH-31pdCbd-gXhPSiG-7hvhtYY#austria-ricardo-demand -Version: 2 -Type: contract -Contract: rgb:Dl4Difx7-VxSWda4-Bv!Z89y-CbiVUkF-0vIxjRy-vvqO77A -Schema: rgb:sch:RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k#brave-dinner-banana -Interface: RGB20Fixed -Check-SHA256: db958c5cca1988c753665fc9a3da383615cbea62f0e1e1e6d7a7add2539d17ec - -0ssI2002ZbAu%+5_6z)DVT-@j4Fp29h04O2(!&-{P^aZh38Qb#nm# -0iX|oIUs*Z=yeHROa_%`=El@tIJ|sRf`I8Lo365whq9yq1JDNn05|{xL_$XkL}g-iXCPs7b7gb^B~W2` -AYpWLWo~q7Z*DpubZBKDVRLh3bRcM9b0BVSAa-GFb!7t42LS+;1d;?(RYFQdLsTGCPb?roPDCJANmNKr -Ra78JP9Q-}Ss+(ISs+YFO-WQqPDd;tR7gc2QbkZwMN>siR6$fpPfk-HK~6* -Ss+tIOiV>mARt9pP*O!xQ%qSPQ$6cNl#87Peve9MNCXZQd1yMRZ>$`K~7X4R8JsONJSu2MN&;uAV@`0MNdX7AVE$w%R9PS(R8JsDPE$}tLsTGCNJSt}QcqAtQdC(iAW&6OLr6hWMN%L^M^Z&aQy^4NAW&6OLr6hWMIcm2 -MIca8Pf$ftR9PV6fSf^7AW2i=fSoKL;((l2NJUabAW2i=fSoKLAXiCLNFYH>Odv)tPf|flAW2R}Pf|@mR7p=xEFe-vP)|}+Q!F4;R6$fl -O+`*rQ!F4LL{CFiO+`*rQy@=LAW}s`Pf|ovAVW`1Lq$?fNlr%~R7gc2P*P7&MN(8*AW%|IR!KxfL?BO6 -AWcC;MIb>|K}k$OLQF*GpK~qIiEFei#Qy@V{MNU*xAWu>tLr+dqR7q4-MNU*xAVOInK~7m9 -Q$tR7gouL?BQ>QdCJrQy@}BP*O!x -MNU*nPDdb5QXo)OQczD)R7p-pAXHBvQbkZwMN>siR3Jf4Ss+tIOiV>mEFe=zK}<{_PES-ILPa1_MNm>j -Q$uAX899LrF$SLqSYTSs+tIR3JuAQdCGFNJUabNlq>x -NlqY8RZ>GpK~qUiM<7&4MIca8Pf$ftR9PTTQXo`8OG!>gAWu|CMN%L^LsUsmP9R7{QbkoxL`708AW&6O -Lr6hWMN%M0K~o@3PgEd5PDCJ6NI^_YAWlzIAW}t4Ss+hNAVE%9AX8OCNFYQ>Q$tKoQ&mz$Q!F4tRa78S -K~zXZQY;`)RZ>GpK~qIiAX7*|OiUnBMNC;BPfko(AWu#pP*qYxNI_FYQsRJ_Qy@=QP9RB6Q&2@iR7p=x -AWudhR7gc2P*P7&MN(8*AVE$4jM@3U0R7gQoAXG?2AW&6OLr6hWMIca8Nkc^-Qbk5gMMG3mAVE$kh3aTNI4>qw4obv;hDB01)TImdq$#?)UpynIxG -faxfkuCkJcvZMe200000000000000001{4bZb@!tY+-a^Vr*qWb8}^Mkc}T^00000GyrpRX*x_=Q!#aT -EoW*(Ic```MlDZcWpq_lYga8cax-;PLsK>_VNqyvIaf7iEjUU=H+KL7&<6n5{J!HJ@Tgs1mpj@U3yhwA -`^&{wC3iS1tkb=;A&LP3007Yk09%X4R5&sPN*yA;lp<^AQ;QQiCWsumMiT;fc;H-Y_W=L^+6MrLj96u3 -I`KP|x6K-jit^gQ+!PC!a#7jT+VjUz9FBwm0004?4*>`O00Ynm0RRC2(FXwl0RY+u0RRC20iX{70RR60 -0juzt(u?g--(Ch+6*7N1n=+qwe6YFx|MoP&lb}4dCJ6ul0T3qu00E#60RaF10iX{70RR600juzt(u?g- --(Ch+6*7N1n=+qwe6YFx|MoP&lb}4dCIA2c00000000010SZz_LNYK$X?SI11XfR6o;2qj;#=~;t^vidEtAC%IlVX)dgF*wOtts}w(E1kon`A59t%UgjW&i*H0009FX>)UR -Wn@!zaBysS0f>xPWn((=JC(Q18jXtb+QHlu3zu?H+0@$e$59-PgaH5qb8uy20oVM#;~wy+U0;_w+8Yau -o__nw#aAVFI4rEwy|f{U0RaF7bY*gFa{*h6$5c2n1xg(vzLX+s=TnOlIwpu5x<(TMczEDkZ1({G0SaMr -b7gc-cWz~J0ssL4000033~6(7b!B8zb#QQOc>w?c00eVzWn%#V0RRPbWpZtE0RRC20SaMrb7gc-cWz~J -0RaF1009nZb8~fNWKC&vZDDj{XaNXxa$#Ze?--0RR613So0|Wpqz>Ze?-- -0RR600S|6(Zbfl*VQfKdZ*^{Ta{&rrb8}^MPj_x*asUAcbaG*Cb7p070uE_&b9H58O=)v&VRU0?WOH?J -aBO)Xb8uy2X=Z6#(b7gc-cWz~J00000009su2y}8`ZgXa3 -asU7T000624{mR6MR9duY(Z^rb#8QX000000S;+%b9H58O=)v&VRU0?00000GyrpRX*x_=Q!#aTEoW*( -Ic```MlDZcWpq_lYga8cax-;PLsK>_VNqyvIaf7iEjUU=H+KLd000X1U)Cjo-i6E2P9x&mnv%Qki+Oba -;k67*blZ=H=TQh>UMA(m1w0!?L{VGDpk+OvDhHAKF%fNXr25$w;Zs!r0000000007000000000O%am^t -lg}6qop{{FTg974FaQ3n`}K{nn9PGH_DcZ;0agu`_oR6wvcum54rF6FkJew+k!36?Lqfl$`8gF)R2-|n -!`LRkztQP;3W%Qi%!_9htpQ3t>=3qD6)+-@LI6MnH0sEektM3d!V}o -0nEa3l8<>f1KA&4t&LI4m}^5aI1iE}_s79eO?HmEkSbfMtWb&n35^vCNG$%?ywDnvz}K{0G9hl&cB^sg --3J`2zr)xjz`xPycM6D}`pk=G7OeqFKI{;-SrsrMkU}5;FWB;W7bg;sK59Oe@c3K=fV3eR7p&1RS^QDd -q`TfM1OfmAZf|a7*gwADFAe3iZ1@l19{2t5VaJV^T`{fc?xMUvnKPbj0R(ezZDp`<(~tJj3|i&b2NlXO -R2^DUyWY#wQk^*F-L`Td370(4qMgjGn~{4aFkgwNr28QlFe*-S#jFZ=4d$x=UULI21Z8+*Y#{__VRL9B -24rt+Y+-UF17U4&CIoP7b#p5OWMOk?Edyk4bS?yXWpZyY18;6+F#~jWZ!!gRXmVv`GX!RDb#gQWW@&b1 -H3M^Lcs2!dWp-t5Hw9&BXJ~Xd1a4_=WjO_7VRB`3UIuJ$WMOk?UjboZ0b*hSV`BkiWC3Mm0cK_aXJ-Lu -XaQ+y0cvUiYij{)YyoX;0d8&qZ*Ku`Z~<{~0djHyb8`W7bOCjB0d{r)cXt7Jcma8N0eX5rD{{BQuNq?v -w$uLzi?1~hlkP@ao_$9uVE}^UN!R2B0b{Bo6zH)>$g+grvznd|(VVK)`s##^Jh_COk!RL4N<*rD#rE}N -PvxSnUK**8Le1-kltSZ7azFKgf3Y*(iUtA%ba`-Pu?^n-fFP~dpvnj-AyBKaJW)+{-ce}5$#DguerIN2 -24rbxWpi{YTdJ&3iT??W6$?l#{@A?G8j--)v|TbGZq;_HaqHbhw}2&v0mUY=J6lL$MhcKn;XgI|zJmp* -01;Q@0XT>R0ssVVZ*FDSKfd5E4dt|K_z&S8_xG@u4Q3HlB(d+LiLJm-R=h;`?dxC37Wb8ul}WgrA) -cw=lK261(7bY*iQ1ZZJ%Xd?z>Z)|K~awG?EWpZO>ZgeFHVQp|_a&uvBWF`t>aBp*Ta&K^GWhV$?a$#d@ -Wpqp^2x4+!V{2t}QYi>wb97~LX>)5T1aNG1b1Ma7Z*6U1ECp?8Zgq1l17vS>E(LRJVRL9N1bSt1Z!iOI -Ze=k8ba!tu1$1a~Wo0u2W^Z+JGz4a8c4ajKb7^=s1#@L~Wo|bGWoc(MgX1!He)Z*DpXb7gI5 -LvL(vZaV~QWpi^p1!Zw{VQf7IXL4m>bY*fr2yt~~b98BMZa)HHbU*@MK|umvLP7#xLqh^zL_`8#MMVN% -Mn(c(M@Ir*NJs)-Nl5}OG^S@OiTh_O-%w{PEG<}Pfr40P*4J2QBeY4Qc?n6Q&R$8R8#_ARaF9C -R#pOES62dGSXcsISy=*KT3QNoaYAxoV{2t}Oj`+JVPk7kY+-X~Tnck>LULhaYh`p&T?J!da%FU025fI+ -VRL9-2x4JlYjkO2YhVFkVF6-d0b^qUWMlzlWdUYp0cU3cXlMaxX#r|#0c&dkY-|B-Z2@j>0dH>saBu-} -aRG920dsQ!baVlAbpdvE0e5!+cz6MMc>#KQ31dQXVPk7$bWD2$aA|O5dyr3U)7OiEGa`mzoq#(6;V_O`>9xR8a*>q2D50xZ(4$R31H0PIsUw_;fcDKIn~;D -0000000000|Nj6000000TX!suv0v9m0LPL+_79KRH|I99{YEOV7tT#ZPWpkW1p!`O$dXTU&2q#dT$Zax -d1hGe8*-eZ2I646q$?$f9S>WJ$5c2n1xg(vzLX+s=TnOlIwpu5x<(TMczEDkZ1)BN1axJ1bQsH&ZxWNw -7!I9y+{RnQn@2DI{;m7Md`c4>2IVr*pq1Y~7nX#oXeWo~q70tIbpY;0)*31nqsX-#QtY-t1vV`Xl1X-#QtY-t4rZE0h2 -Zw3iuWn*bgX=8G42MS|lZggo)X=8G42n23nZf^+)WMyM%PGN3u3JGInZggo*VQy~=1aN6%Zwv@zWn*bj -X=85<31ek$bZJm&V{Z-xW@T-3Zx0D%Wn*bZWo>kC5DH^uZggozWo>kC5d>j$bZ-(~UdWP9bIo$ZB3zcM -M|oyg?;CQQqXyz&yre57i5(9G0)iue^mXvL0b>G|!V30Z)+K@7h0D=S -BjVedlDqGVd368bwG2#j+mD9lQD0sr<;4X&8%0D>TgISeJ)kNFk^3Xf*%skbRRcZ*dS!BNFavLH -WibPEcW*KUbZByAWite3Z*_7s1ZHV=WiUrS2@UrbB_UrkK{UrtT}Ur$d0Ur8 -UsO~AUsY8CUshHEUsqQGUszZIUs+iKUs_rLVPOGcVgX}g0c2zWWn}?oW&vks0cdCeX=wp!Y5{9&0c>mm -ZEXQ=ZUJv^0dQ~uad821ashL50d#Z$b#(!Db^&*H0eE-;d3gbPdSj|16zH)>$g+grvznd|(VVK)`s##^ -Jh_COk!RL4N(lR@SaKRYGgJn%Xv1$>f_VvG%;GuzyszPjx|liD+IRr~000000093000000004kq#k^Az -$U%@qU7>2Bz={du0O&G0&#r1CLJBFZ06hf(#5#SRxw8U!bIFfg*5RxK^~=*jK)}Ad3JOG^S@OiTh_O-%w{PEG<}Pfr40P*4J2QBeY4Qc?n6Q&R$8R8#_ARaF9CR#pOES62dGSXcsI -Sy=*KT3P{NVF6-d0b^qUWMlzlWdUYp0cU3cXlMaxX#r|#0c&dkY-|B-Z2@j>0dH>saBu-}aRG920dsQ! -baVlAbpdvE0e5!+cz6MMc>#KQh>TceV>4NmyOwH13hJ -J{u?^n-fFP~dpvnj-AyBKaJW)+{-ce}5$#DguerIN21_K0id2nSM -uyu|U!T^j90F36+)E=H0H{s0>nH0sEektM3d!V}qb9G{Ld2nSf*z$T8ClZi8YCe|m_*?{lv>_T7tkE!8 -{87}TyWT7ZV`yP=b7gcd*z$T8ClZi8YCe|m_*?{lv>_T7tkE!8{87}TyWT9nkIU)BIae{Jw9R4r0N>}O -)+shqImKG);D@8R3aUm3Jkg?^%&nV|dnPbniKwLeAs8?!PIJYq3V03Xs{mee0000000000KL7v#00000 -#5#SRxw8U!bIFfg*5RxK^~=*jK)}Ad3JH<(%oY0=TGqa6l5KfYJkC@$v(fAa&d%-e7ws4kFK+d0H97bAybczVb@xPq-Dzr4oJgUK7Oif -U&jRjKPz&##IG7-47St%2#c>Z5R>jkTb_MKDq#SEVo@@XB+#WAdR)2C|*D$SwhJOvD$-0{Gfin@` -^Yz ->$s@6fa*%L>wyFU00eGtZe`d%zThtn<+N=058)p7{qSMOjh9_9t?BNfyg->Vo@@aGb8l^B+#WAdR)2C| -*D$SwhJOvD$-0{Gfin@`G@u4Q3HlB(d+LiLJm-R=h;`?dxBvhE0000004D$d000000QnaP1l_I#dHB_@bgMhk0_N&La@nc5 -HwP6O+keCip#vHLVPOGcVgX}g0c2zWWn}?oW&vks0cdCeX=wp!Y5{9&0c>mmZEXQ=ZUJv^0dQ~uad821 -ashL50d#Z$b#(!Db^&*H0eE-;d3gbPdi$wZavD7|R0gwX!*5!Gc?n?5;yM1jui=Thm^szjcmV+b0|P-! -RR}^*L`g?QQ&a;|M?xV03jhEB(4Y?i2MYiJ01F5J01E*E0La=00XZ-L(V!0j2Lu2B0RR910000 - ------END RGB CONSIGNMENT----- - - diff --git a/psbt/Cargo.toml b/psbt/Cargo.toml index 07714460..1a179e66 100644 --- a/psbt/Cargo.toml +++ b/psbt/Cargo.toml @@ -27,8 +27,8 @@ rgb-std = { workspace = true } [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2" -rand = { version = "0.8.4", optional = true } -getrandom = { version = "0.2", features = ["js"] } +rand = { version = "0.9.1", optional = true } +getrandom = { version = "0.3", features = ["wasm_js"] } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3" diff --git a/psbt/src/lib.rs b/psbt/src/lib.rs index 510f312d..e460af2b 100644 --- a/psbt/src/lib.rs +++ b/psbt/src/lib.rs @@ -29,23 +29,22 @@ use bp::dbc::tapret::TapretProof; use bp::seals::txout::CloseMethod; pub use bpstd::psbt::*; pub use rgb::*; -use rgbstd::containers::{AnchorSet, Batch, Fascia, PubWitness}; +use rgbstd::containers::{Batch, Fascia, PubWitness, SealWitness}; pub use self::rgb::{ - ProprietaryKeyRgb, RgbExt, RgbInExt, RgbOutExt, RgbPsbtError, PSBT_GLOBAL_RGB_TRANSITION, - PSBT_IN_RGB_CONSUMED_BY, PSBT_OUT_RGB_VELOCITY_HINT, PSBT_RGB_PREFIX, + Opids, ProprietaryKeyRgb, RgbExt, RgbInExt, RgbPsbtError, PSBT_GLOBAL_RGB_TRANSITION, + PSBT_IN_RGB_CONSUMED_BY, PSBT_RGB_PREFIX, }; -#[derive(Clone, Eq, PartialEq, Debug, Display, Error)] +#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] #[display(doc_comments)] pub enum EmbedError { /// provided transaction batch references inputs which are absent from the /// PSBT. Possible it was created for a different PSBT. AbsentInputs, - /// the provided PSBT is invalid since it doublespends on some of its - /// inputs. - PsbtRepeatedInputs, + #[from] + Rgb(RgbPsbtError), } #[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] @@ -62,9 +61,8 @@ pub enum CommitError { #[display(doc_comments)] pub enum ExtractError {} -// TODO: Batch must be homomorphic by the outpoint type (chain) - pub trait RgbPsbt { + #[allow(clippy::result_large_err)] fn rgb_embed(&mut self, batch: Batch) -> Result<(), EmbedError>; #[allow(clippy::result_large_err)] fn rgb_commit(&mut self) -> Result; @@ -78,9 +76,7 @@ impl RgbPsbt for Psbt { let mut inputs = info.inputs.release(); for input in self.inputs_mut() { if inputs.remove(&input.prevout().outpoint()) { - input - .set_rgb_consumer(contract_id, info.id) - .map_err(|_| EmbedError::PsbtRepeatedInputs)?; + input.set_rgb_consumer(contract_id, info.id)?; } } if !inputs.is_empty() { @@ -100,15 +96,18 @@ impl RgbPsbt for Psbt { let close_method = self .rgb_close_method()? .ok_or(RgbPsbtError::NoCloseMethod)?; - let anchor = match close_method { - CloseMethod::TapretFirst => AnchorSet::Tapret(self.dbc_commit::()?), - CloseMethod::OpretFirst => AnchorSet::Opret(self.dbc_commit::()?), + let (merkle_block, dbc_proof) = match close_method { + CloseMethod::TapretFirst => self + .dbc_commit::() + .map(|(mb, proof)| (mb, proof.into()))?, + CloseMethod::OpretFirst => self + .dbc_commit::() + .map(|(mb, proof)| (mb, proof.into()))?, }; - // TODO: Use signed transaction here! let witness = PubWitness::with(self.to_unsigned_tx().into()); + let seal_witness = SealWitness::new(witness, merkle_block, dbc_proof); Ok(Fascia { - witness, - anchor, + seal_witness, bundles, }) } diff --git a/psbt/src/rgb.rs b/psbt/src/rgb.rs index c4e389f6..b311b8e3 100644 --- a/psbt/src/rgb.rs +++ b/psbt/src/rgb.rs @@ -22,15 +22,14 @@ use std::collections::{BTreeMap, BTreeSet}; use amplify::confinement::{Confined, SmallOrdMap, U24}; -use amplify::{confinement, FromSliceError}; +use amplify::{confinement, FromSliceError, Wrapper}; use bp::dbc::Method; use bp::seals::txout::CloseMethod; use bpstd::psbt; -use bpstd::psbt::{KeyAlreadyPresent, KeyMap, MpcPsbtError, PropKey, Psbt}; +use bpstd::psbt::{KeyMap, MpcPsbtError, PropKey, Psbt}; use commit_verify::mpc; -use rgbstd::containers::VelocityHint; use rgbstd::{ - ContractId, InputMap, MergeReveal, MergeRevealError, OpId, Operation, Transition, + ContractId, InputOpids, MergeReveal, MergeRevealError, OpId, Operation, Transition, TransitionBundle, Vin, }; use strict_encoding::{DeserializeError, StrictDeserialize, StrictSerialize}; @@ -50,12 +49,50 @@ pub const PSBT_GLOBAL_RGB_TRANSITION: u64 = 0x01; /// Proprietary key subtype for storing information on which close method /// should be used. pub const PSBT_GLOBAL_RGB_CLOSE_METHOD: u64 = 0x02; +/// Proprietary key subtype to signal that tapret host has been put on change. +pub const PSBT_GLOBAL_RGB_TAP_HOST_CHANGE: u64 = 0x03; /// Proprietary key subtype for storing RGB state transition operation id which /// consumes this input. pub const PSBT_IN_RGB_CONSUMED_BY: u64 = 0x01; -/// Proprietary key subtype for storing hint for the velocity of the state -/// which can be assigned to the provided output. -pub const PSBT_OUT_RGB_VELOCITY_HINT: u64 = 0x01; + +#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Hash, Debug, From)] +#[wrapper(Deref)] +#[wrapper_mut(DerefMut)] +pub struct Opids(Vec); + +impl Opids { + pub fn new(opids: Vec) -> Self { Self(opids) } + + pub fn serialize(&self) -> Vec { + let opid_size = std::mem::size_of::(); + let op_ids = &self.0; + let mut bytes = Vec::with_capacity(op_ids.len() * opid_size); + for opid in op_ids { + bytes.extend(opid.to_byte_array()); + } + bytes + } + + #[allow(clippy::result_large_err)] + pub fn deserialize(bytes: &[u8]) -> Result { + let opid_size = std::mem::size_of::(); + let bytes_len = bytes.len(); + if bytes_len % opid_size != 0 { + return Err(RgbPsbtError::InvalidOpidsData(format!( + "Input data length {bytes_len} is not a multiple of {opid_size}" + ))); + } + let len = bytes.len() / opid_size; + let mut op_ids = Vec::with_capacity(len); + for chunk in bytes.chunks_exact(opid_size) { + let opid = OpId::copy_from_slice(chunk).map_err(|e| { + RgbPsbtError::InvalidOpidsData(format!("Error deserializing an OpId: {:?}", e)) + })?; + op_ids.push(opid); + } + Ok(Opids::new(op_ids)) + } +} /// Extension trait for static functions returning RGB-related proprietary keys. pub trait ProprietaryKeyRgb { @@ -67,6 +104,7 @@ pub trait ProprietaryKeyRgb { data: opid.to_vec().into(), } } + /// Constructs [`PSBT_GLOBAL_RGB_CLOSE_METHOD`] proprietary key. fn rgb_close_method() -> PropKey { PropKey { @@ -85,11 +123,11 @@ pub trait ProprietaryKeyRgb { } } - /// Constructs [`PSBT_OUT_RGB_VELOCITY_HINT`] proprietary key. - fn rgb_out_velocity_hint() -> PropKey { + /// Constructs [`PSBT_GLOBAL_RGB_TAP_HOST_CHANGE`] proprietary key. + fn rgb_tapret_host_on_change() -> PropKey { PropKey { identifier: PSBT_RGB_PREFIX.to_owned(), - subtype: PSBT_OUT_RGB_VELOCITY_HINT, + subtype: PSBT_GLOBAL_RGB_TAP_HOST_CHANGE, data: none!(), } } @@ -114,13 +152,19 @@ pub enum RgbPsbtError { /// PSBT contains no contract consumers information NoContractConsumers, - /// contract {0} listed in the PSBT has zero known transition information. - NoTransitions(ContractId), + /// contract {0} listed in the PSBT has an invalid number of known transitions {1}. + InvalidTransitionsNumber(ContractId, usize), + + /// inputs listed in the PSBT have an invalid number {0}. + InvalidInputsNumber(usize), /// invalid contract id data. #[from(FromSliceError)] InvalidContractId, + /// invalid opids data: {0}. + InvalidOpidsData(String), + /// PSBT doesn't provide information about close method. NoCloseMethod, @@ -156,41 +200,53 @@ pub trait RgbExt { fn rgb_contract_consumers( &self, contract_id: ContractId, - ) -> Result, FromSliceError>; + ) -> Result, Vin)>, RgbPsbtError>; - fn rgb_op_ids(&self, contract_id: ContractId) -> Result, FromSliceError>; + fn rgb_op_ids(&self, contract_id: ContractId) -> Result, RgbPsbtError>; fn rgb_transition(&self, opid: OpId) -> Result, RgbPsbtError>; fn rgb_close_method(&self) -> Result, RgbPsbtError>; + fn rgb_tapret_host_on_change(&self) -> bool; + fn set_rgb_close_method(&mut self, close_method: CloseMethod); + fn set_rgb_tapret_host_on_change(&mut self); + fn push_rgb_transition(&mut self, transition: Transition) -> Result; fn rgb_bundles(&self) -> Result, RgbPsbtError> { let mut map = BTreeMap::new(); for contract_id in self.rgb_contract_ids()? { - let mut input_map: SmallOrdMap = SmallOrdMap::new(); + let mut input_map: SmallOrdMap = SmallOrdMap::new(); let mut known_transitions: SmallOrdMap = SmallOrdMap::new(); let contract_consumers = self.rgb_contract_consumers(contract_id)?; if contract_consumers.is_empty() { return Err(RgbPsbtError::NoContractConsumers); } - for (opid, vin) in contract_consumers { - let transition = self.rgb_transition(opid)?; - input_map.insert(vin, opid)?; - if let Some(transition) = transition { - known_transitions.insert(opid, transition)?; + for (opids, vin) in contract_consumers { + for opid in &opids { + let transition = self.rgb_transition(*opid)?; + if let Some(transition) = transition { + known_transitions.insert(*opid, transition)?; + } } + let opids_len = opids.len(); + let opids = + InputOpids::from(Confined::try_from(opids).map_err(|_| { + RgbPsbtError::InvalidTransitionsNumber(contract_id, opids_len) + })?); + input_map.insert(vin, opids)?; } + let input_map_len = input_map.len(); + let known_transitions_len = known_transitions.len(); let bundle = TransitionBundle { - input_map: InputMap::from( - Confined::try_from(input_map.release()) - .map_err(|_| RgbPsbtError::NoTransitions(contract_id))?, - ), - known_transitions: Confined::try_from(known_transitions.release()) - .map_err(|_| RgbPsbtError::NoTransitions(contract_id))?, + input_map: Confined::try_from(input_map.release()) + .map_err(|_| RgbPsbtError::InvalidInputsNumber(input_map_len))?, + known_transitions: Confined::try_from(known_transitions.release()).map_err( + |_| RgbPsbtError::InvalidTransitionsNumber(contract_id, known_transitions_len), + )?, }; map.insert(contract_id, bundle); } @@ -222,20 +278,23 @@ impl RgbExt for Psbt { fn rgb_contract_consumers( &self, contract_id: ContractId, - ) -> Result, FromSliceError> { - let mut consumers: BTreeSet<(OpId, Vin)> = bset! {}; + ) -> Result, Vin)>, RgbPsbtError> { + let mut consumers: BTreeSet<(BTreeSet, Vin)> = bset! {}; for (no, input) in self.inputs().enumerate() { - if let Some(opid) = input.rgb_consumer(contract_id)? { - consumers.insert((opid, Vin::from_u32(no as u32))); + if let Some(opids) = input.rgb_consumer(contract_id)? { + consumers.insert((BTreeSet::from_iter(opids), Vin::from_u32(no as u32))); } } Ok(consumers) } - fn rgb_op_ids(&self, contract_id: ContractId) -> Result, FromSliceError> { - self.inputs() - .filter_map(|input| input.rgb_consumer(contract_id).transpose()) - .collect() + fn rgb_op_ids(&self, contract_id: ContractId) -> Result, RgbPsbtError> { + self.inputs().try_fold(BTreeSet::new(), |mut set, input| { + if let Some(ids) = input.rgb_consumer(contract_id)? { + set.extend(ids); + } + Ok(set) + }) } fn rgb_transition(&self, opid: OpId) -> Result, RgbPsbtError> { @@ -259,20 +318,26 @@ impl RgbExt for Psbt { Err(RgbPsbtError::InvalidCloseMethod) } + fn rgb_tapret_host_on_change(&self) -> bool { + self.has_proprietary(&PropKey::rgb_tapret_host_on_change()) + } + fn set_rgb_close_method(&mut self, close_method: CloseMethod) { let _ = self.push_proprietary(PropKey::rgb_close_method(), vec![close_method as u8]); } + fn set_rgb_tapret_host_on_change(&mut self) { + let _ = self.push_proprietary(PropKey::rgb_tapret_host_on_change(), vec![]); + } + fn push_rgb_transition(&mut self, mut transition: Transition) -> Result { let opid = transition.id(); let prev_transition = self.rgb_transition(opid)?; if let Some(ref prev_transition) = prev_transition { - transition = transition - .merge_reveal(prev_transition.clone()) - .map_err(|err| { - RgbPsbtError::UnrelatedTransitions(prev_transition.id(), opid, err) - })?; + transition.merge_reveal(prev_transition).map_err(|err| { + RgbPsbtError::UnrelatedTransitions(prev_transition.id(), opid, err) + })?; } let serialized_transition = transition .to_strict_serialized::() @@ -314,6 +379,7 @@ impl RgbExt for Psbt { } } +#[allow(clippy::result_large_err)] pub trait RgbInExt { /// Returns information which state transition consumes this PSBT input. /// @@ -321,7 +387,7 @@ pub trait RgbInExt { /// this proprietary key to a standard one. In this case, the invalid /// data will be filtered at the moment of PSBT deserialization and this /// function will return `None` only in situations when the key is absent. - fn rgb_consumer(&self, contract_id: ContractId) -> Result, FromSliceError>; + fn rgb_consumer(&self, contract_id: ContractId) -> Result>, RgbPsbtError>; /// Adds information about state transition consuming this PSBT input. /// @@ -340,71 +406,40 @@ pub trait RgbInExt { &mut self, contract_id: ContractId, opid: OpId, - ) -> Result; + ) -> Result; } impl RgbInExt for psbt::Input { - fn rgb_consumer(&self, contract_id: ContractId) -> Result, FromSliceError> { + fn rgb_consumer(&self, contract_id: ContractId) -> Result>, RgbPsbtError> { let Some(data) = self .proprietary .get(&PropKey::rgb_in_consumed_by(contract_id)) else { return Ok(None); }; - Ok(Some(OpId::copy_from_slice(data)?)) + let opids = Opids::deserialize(data)?.into_inner(); + Ok(Some(opids)) } fn set_rgb_consumer( &mut self, contract_id: ContractId, opid: OpId, - ) -> Result { + ) -> Result { let key = PropKey::rgb_in_consumed_by(contract_id); - match self.rgb_consumer(contract_id) { - Ok(None) | Err(_) => { - let _ = self.push_proprietary(key, opid.to_vec()); - Ok(true) + Ok(match self.rgb_consumer(contract_id)? { + None => { + let opids = Opids::new(vec![opid]); + let _ = self.push_proprietary(key, opids.serialize()); + true } - Ok(Some(id)) if id == opid => Ok(false), - Ok(Some(_)) => Err(KeyAlreadyPresent(key)), - } - } -} - -pub trait RgbOutExt { - /// Returns hint for the velocity of the state which may be assigned to the - /// provided output. - /// - /// We do not error on invalid data in order to support future update of - /// this proprietary key to a standard one. In this case, the invalid - /// data will be filtered at the moment of PSBT deserialization and this - /// function will return `None` only in situations when the key is absent. - fn rgb_velocity_hint(&self) -> Option; - - /// Adds hint for the velocity of the state which may be assigned to the - /// PSBT output. - /// - /// # Returns - /// - /// `false`, if a velocity hint was already present in the input and - /// `true` otherwise. - fn set_rgb_velocity_hint(&mut self, hint: VelocityHint) -> bool; -} - -impl RgbOutExt for psbt::Output { - fn rgb_velocity_hint(&self) -> Option { - let data = self.proprietary.get(&PropKey::rgb_out_velocity_hint())?; - if data.len() != 1 { - None - } else { - data.first().map(VelocityHint::with_value) - } - } - - fn set_rgb_velocity_hint(&mut self, hint: VelocityHint) -> bool { - let prev = self.rgb_velocity_hint(); - self.push_proprietary(PropKey::rgb_out_velocity_hint(), vec![hint as u8]) - .ok(); - Some(hint) == prev + Some(ids) if ids.contains(&opid) => false, + Some(mut opids) => { + opids.push(opid); + let opids = Opids::new(opids); + self.insert_proprietary(key, opids.serialize().into()); + true + } + }) } } diff --git a/src/descriptor.rs b/src/descriptor.rs index 8c48b016..b2277512 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -19,7 +19,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::{BTreeSet, HashMap}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::fmt::{self, Display, Formatter}; use std::iter; use std::str::FromStr; @@ -38,17 +38,9 @@ use bpstd::{ use commit_verify::CommitVerify; use indexmap::IndexMap; -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] -#[display("terminal derivation {0} already has a taptweak assigned")] -pub struct TapTweakAlreadyAssigned(pub Terminal); - pub trait DescriptorRgb: Descriptor { fn close_method(&self) -> CloseMethod; - fn add_tapret_tweak( - &mut self, - terminal: Terminal, - tweak: TapretCommitment, - ) -> Result<(), TapTweakAlreadyAssigned>; + fn add_tapret_tweak(&mut self, terminal: Terminal, tweak: TapretCommitment); } #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] @@ -119,19 +111,24 @@ impl From for Keychain { )] pub struct TapretKey { pub tr: TrKey, - // TODO: Allow multiple tweaks per index by introducing derivation using new Terminal trait - pub tweaks: HashMap, + pub tweaks: BTreeMap>, } impl Display for TapretKey { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "tapret({},tweaks(", self.tr.as_internal_key())?; let mut iter = self.tweaks.iter().peekable(); - while let Some((term, tweak)) = iter.next() { + while let Some((term, tweaks)) = iter.next() { if term.keychain != RgbKeychain::Tapret.into() { - write!(f, "{}/", term.keychain)?; + write!(f, "{}/{}=", term.keychain, term.index)?; + } + let mut commitment_iter = tweaks.iter().peekable(); + while let Some(tweak) = commitment_iter.next() { + write!(f, "{tweak}")?; + if commitment_iter.peek().is_some() { + f.write_str(",")?; + } } - write!(f, "{}={tweak}", term.index)?; if iter.peek().is_some() { f.write_str(";")?; } @@ -159,19 +156,21 @@ impl Derive for TapretKey { &self, keychain: impl Into, index: impl Into, - ) -> DerivedScript { + ) -> impl Iterator { let keychain = keychain.into(); let index = index.into(); let terminal = Terminal::new(keychain, index); - let internal_key = self.tr.as_internal_key().derive(keychain, index); - if keychain.into_inner() == RgbKeychain::Tapret as u8 { - if let Some(tweak) = self.tweaks.get(&terminal) { + let mut derived_scripts = Vec::with_capacity(self.tweaks.len() + 1); + for internal_key in self.tr.as_internal_key().derive(keychain, index) { + derived_scripts.push(DerivedScript::TaprootKeyOnly(internal_key.into())); + for tweak in self.tweaks.get(&terminal).into_iter().flatten() { let script_commitment = TapScript::commit(tweak); let tap_tree = TapTree::with_single_leaf(script_commitment); - return DerivedScript::TaprootScript(internal_key.into(), tap_tree); + let script = DerivedScript::TaprootScript(internal_key.into(), tap_tree); + derived_scripts.push(script); } } - DerivedScript::TaprootKeyOnly(internal_key.into()) + derived_scripts.into_iter() } } @@ -229,16 +228,8 @@ impl Descriptor for TapretKey { impl DescriptorRgb for TapretKey { fn close_method(&self) -> CloseMethod { CloseMethod::TapretFirst } - fn add_tapret_tweak( - &mut self, - terminal: Terminal, - tweak: TapretCommitment, - ) -> Result<(), TapTweakAlreadyAssigned> { - if self.tweaks.contains_key(&terminal) { - return Err(TapTweakAlreadyAssigned(terminal)); - } - self.tweaks.insert(terminal, tweak); - Ok(()) + fn add_tapret_tweak(&mut self, terminal: Terminal, tweak: TapretCommitment) { + self.tweaks.entry(terminal).or_default().insert(tweak); } } @@ -292,10 +283,15 @@ impl Derive for RgbDescr { } } - fn derive(&self, change: impl Into, index: impl Into) -> DerivedScript { + fn derive( + &self, + change: impl Into, + index: impl Into, + ) -> impl Iterator { + // collecting as a workaround for different opaque types match self { - RgbDescr::Wpkh(d) => d.derive(change, index), - RgbDescr::TapretKey(d) => d.derive(change, index), + RgbDescr::Wpkh(d) => d.derive(change, index).collect::>().into_iter(), + RgbDescr::TapretKey(d) => d.derive(change, index).collect::>().into_iter(), } } } @@ -375,11 +371,7 @@ where Self: Derive } } - fn add_tapret_tweak( - &mut self, - terminal: Terminal, - tweak: TapretCommitment, - ) -> Result<(), TapTweakAlreadyAssigned> { + fn add_tapret_tweak(&mut self, terminal: Terminal, tweak: TapretCommitment) { match self { RgbDescr::Wpkh(_) => panic!("adding tapret tweak to non-taproot descriptor"), RgbDescr::TapretKey(d) => d.add_tapret_tweak(terminal, tweak), @@ -396,3 +388,60 @@ impl From for RgbDescr { } } } + +#[cfg(test)] +mod test { + use std::str::FromStr; + + use bp::dbc::tapret::TapretCommitment; + use bpstd::{DeriveSet, Idx, Keychain, NormalIndex, Terminal, TrKey, XpubDerivable}; + use commit_verify::mpc::Commitment; + use strict_types::StrictDumb; + + use super::TapretKey; + use crate::DescriptorRgb; + + #[test] + fn tapret_key_display() { + let xpub_str = "[643a7adc/86h/1h/0h]tpubDCNiWHaiSkgnQjuhsg9kjwaUzaxQjUcmhagvYzqQ3TYJTgFGJstVaqnu4yhtFktBhCVFmBNLQ5sN53qKzZbMksm3XEyGJsEhQPfVZdWmTE2/<0;1>/*"; + let xpub = XpubDerivable::from_str(xpub_str).unwrap(); + let internal_key: TrKey<::XOnly> = TrKey::from(xpub.clone()); + + // no tweaks + let mut tapret_key = TapretKey::from(internal_key); + assert_eq!(format!("{tapret_key}"), format!("tapret({xpub_str},tweaks())")); + + // add a tweak to a new terminal + let terminal = Terminal::new(Keychain::INNER, NormalIndex::ZERO); + let tweak = TapretCommitment::with(Commitment::strict_dumb(), 2); + tapret_key.add_tapret_tweak(terminal, tweak); + assert_eq!( + format!("{tapret_key}"), + format!("tapret({xpub_str},tweaks(1/0=00000000000000000000000000000000000000000s))") + ); + + // add another tweak to a new terminal + let terminal = Terminal::new(Keychain::from(7), NormalIndex::from(12u8)); + let tweak = TapretCommitment::with(Commitment::strict_dumb(), 5); + tapret_key.add_tapret_tweak(terminal, tweak.clone()); + assert_eq!( + format!("{tapret_key}"), + format!( + "tapret({xpub_str},tweaks(1/0=00000000000000000000000000000000000000000s;7/\ + 12=00000000000000000000000000000000000000001p))" + ) + ); + + // add another tweak to an existing terminal + let tweak = TapretCommitment::with(Commitment::strict_dumb(), 2); + tapret_key.add_tapret_tweak(terminal, tweak); + assert_eq!( + format!("{tapret_key}"), + format!( + "tapret({xpub_str},tweaks(1/0=00000000000000000000000000000000000000000s;7/\ + 12=00000000000000000000000000000000000000000s,\ + 00000000000000000000000000000000000000001p))" + ) + ); + } +} diff --git a/src/errors.rs b/src/errors.rs index 1eb856e5..6b0e4adb 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -25,19 +25,18 @@ use std::convert::Infallible; use std::io; use amplify::IoError; -use bp::seals::txout::CloseMethod; use bpstd::Psbt; use nonasync::persistence::PersistenceError; use psrgbt::{CommitError, ConstructionError, EmbedError, TapretKeyError}; -use rgbstd::containers::LoadError; -use rgbstd::interface::{BuilderError, ContractError}; +use rgbstd::containers::{LoadError, TransitionInfoError}; +use rgbstd::contract::{BuilderError, ContractError}; use rgbstd::persistence::{ - ComposeError, ConsignError, ContractIfaceError, FasciaError, Stock, StockError, StockErrorAll, - StockErrorMem, + ComposeError, ConsignError, FasciaError, Stock, StockError, StockErrorAll, StockErrorMem, }; +use rgbstd::{AssignmentType, ChainNet}; use strict_types::encoding::Ident; -use crate::{validation, TapTweakAlreadyAssigned}; +use crate::validation; #[derive(Debug, Display, Error, From)] #[display(inner)] @@ -86,17 +85,19 @@ pub enum WalletError { #[display(doc_comments)] IncompleteContract(validation::Status), + /// cannot find the terminal to add the tapret tweak to. + NoTweakTerminal, + /// resolver error: {0} #[display(doc_comments)] Resolver(String), #[from(StockError)] #[from(StockErrorAll)] - #[from(StockErrorMem)] #[display(inner)] Stock(String), - #[cfg(feature = "serde_yaml")] + #[cfg(feature = "cli")] #[from] Yaml(serde_yaml::Error), @@ -126,19 +127,18 @@ pub enum PayError { #[derive(Debug, Display, Error, From)] #[display(doc_comments)] pub enum CompositionError { - /// unspecified contract. + /// invoice doesn't specify a contract. NoContract, - /// unspecified interface. - NoIface, + /// invoice doesn't provide information about the assignment type and it's impossible to derive + /// which assignment type should be used from the schema. + NoAssignmentType, - /// invoice doesn't provide information about the operation, and the used - /// interface do not define default operation. - NoOperation, + /// invoice doesn't provide information about the assignment state + NoAssignmentState, - /// invoice doesn't provide information about the assignment type, and the - /// used interface do not define default assignment type. - NoAssignment, + /// invoice specifies an unknown contract. + UnknownContract, /// state provided via PSBT inputs is not sufficient to cover invoice state /// requirements. @@ -147,16 +147,11 @@ pub enum CompositionError { /// the invoice has expired. InvoiceExpired, - /// the invoice doesn't support the contract close method {0} - InvoiceUnsupportsCloseMethod(CloseMethod), - - /// the wallet descriptor doesn't support the contract close method {0} - WalletUnsupportsCloseMethod(CloseMethod), + /// invoice specifies a schema which is not valid for the specified contract. + InvalidSchema, - /// one of the RGB assignments spent require presence of tapret output - - /// even this is not a taproot wallet. Unable to create a valid PSBT, manual - /// work is needed. - TapretRequired, + /// invoice requesting chain-network pair {0} but contract commits to a different one ({1}) + InvoiceBeneficiaryWrongChainNet(ChainNet, ChainNet), /// non-fungible state is not yet supported by the invoices. Unsupported, @@ -167,16 +162,43 @@ pub enum CompositionError { #[from] #[display(inner)] - Interface(ContractError), + Contract(ContractError), #[from] #[display(inner)] Embed(EmbedError), + /// no outputs available to store state of type {0} + NoExtraOrChange(AssignmentType), + + /// cannot find an output where to put the tapret commitment. + NoOutputForTapretCommitment, + + /// the provided PSBT doesn't pay any sats to the RGB beneficiary address. + NoBeneficiaryOutput, + + /// beneficiary output number is given when secret seal is used. + BeneficiaryVout, + + /// the spent UTXOs contain too many seals which can't fit the state + /// transition input limit. + TooManyInputs, + + #[from] + #[display(inner)] + Transition(TransitionInfoError), + + /// the operation produces too many extra state transitions which can't fit + /// the container requirements. + TooManyExtras, + + #[from] + #[display(inner)] + Builder(BuilderError), + #[from(String)] #[from(StockError)] #[from(StockErrorMem)] - #[from(StockErrorMem)] #[display(inner)] Stock(String), } @@ -193,16 +215,6 @@ pub enum CompletionError { /// the provided PSBT has conflicting descriptor in the taptweak output. InconclusiveDerivation, - /// the invoice doesn't support the contract close method {0} - InvoiceUnsupportsCloseMethod(CloseMethod), - - /// the wallet descriptor doesn't support the contract close method {0} - WalletUnsupportsCloseMethod(CloseMethod), - - #[from] - #[display(inner)] - MultipleTweaks(TapTweakAlreadyAssigned), - #[from] #[display(inner)] TapretKey(TapretKeyError), @@ -217,3 +229,7 @@ pub enum CompletionError { #[display(inner)] Stock(String), } + +impl From for CompletionError { + fn from(_: Infallible) -> Self { unreachable!() } +} diff --git a/src/filters.rs b/src/filters.rs index 8be3f1fd..ff574d59 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -20,7 +20,7 @@ // limitations under the License. use bpwallet::{Layer2, Wallet}; -use rgbstd::interface::AssignmentsFilter; +use rgbstd::contract::AssignmentsFilter; use crate::{DescriptorRgb, Outpoint, Txid}; diff --git a/src/indexers/any.rs b/src/indexers/any.rs deleted file mode 100644 index b40c952c..00000000 --- a/src/indexers/any.rs +++ /dev/null @@ -1,132 +0,0 @@ -// RGB smart contracts for Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2024 by -// Zoe Faltibà -// Rewritten in 2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::collections::HashMap; - -use bp::{Tx, Txid}; -use rgbstd::containers::Consignment; -use rgbstd::validation::{ResolveWitness, WitnessResolverError}; -use rgbstd::ChainNet; - -use crate::vm::WitnessOrd; - -// We need to repeat methods of `WitnessResolve` trait here to avoid making -// wrappers around resolver types. TODO: Use wrappers instead -pub trait RgbResolver: Send { - fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), String>; - fn resolve_pub_witness(&self, txid: Txid) -> Result, String>; - fn resolve_pub_witness_ord(&self, txid: Txid) -> Result; -} - -/// Type that contains any of the [`Resolver`] types defined by the library -#[derive(From)] -#[non_exhaustive] -pub struct AnyResolver { - inner: Box, - consignment_txes: HashMap, -} - -impl AnyResolver { - #[cfg(feature = "electrum_blocking")] - pub fn electrum_blocking(url: &str, config: Option) -> Result { - Ok(AnyResolver { - inner: Box::new( - electrum::Client::from_config(url, config.unwrap_or_default()) - .map_err(|e| e.to_string())?, - ), - consignment_txes: Default::default(), - }) - } - - #[cfg(feature = "esplora_blocking")] - pub fn esplora_blocking(url: &str, config: Option) -> Result { - Ok(AnyResolver { - inner: Box::new( - esplora::BlockingClient::from_config(url, config.unwrap_or_default()) - .map_err(|e| e.to_string())?, - ), - consignment_txes: Default::default(), - }) - } - - #[cfg(feature = "mempool_blocking")] - pub fn mempool_blocking(url: &str, config: Option) -> Result { - Ok(AnyResolver { - inner: Box::new(super::mempool_blocking::MemPoolClient::new( - url, - config.unwrap_or_default(), - )?), - consignment_txes: Default::default(), - }) - } - - pub fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), String> { - self.inner.check_chain_net(chain_net) - } - - /// Add to the resolver the TXs found in the consignment bundles. Those TXs - /// will not be resolved by an indexer and will be considered tentative. - /// Use with caution, this could allow accepting a consignment containing TXs that have not - /// been broadcasted. - pub fn add_consignment_txes(&mut self, consignment: &Consignment) { - self.consignment_txes.extend( - consignment - .bundles - .iter() - .filter_map(|bw| bw.pub_witness.tx().cloned()) - .map(|tx| (tx.txid(), tx)), - ); - } -} - -impl ResolveWitness for AnyResolver { - fn resolve_pub_witness(&self, witness_id: Txid) -> Result { - if let Some(tx) = self.consignment_txes.get(&witness_id) { - return Ok(tx.clone()); - } - - self.inner - .resolve_pub_witness(witness_id) - .map_err(|e| WitnessResolverError::Other(witness_id, e)) - .and_then(|r| r.ok_or(WitnessResolverError::Unknown(witness_id))) - } - - fn resolve_pub_witness_ord( - &self, - witness_id: Txid, - ) -> Result { - if self.consignment_txes.contains_key(&witness_id) { - return Ok(WitnessOrd::Tentative); - } - - self.inner - .resolve_pub_witness_ord(witness_id) - .map_err(|e| WitnessResolverError::Other(witness_id, e)) - } - - fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), WitnessResolverError> { - self.inner - .check_chain_net(chain_net) - .map_err(|_| WitnessResolverError::WrongChainNet) - } -} diff --git a/src/indexers/electrum_blocking.rs b/src/indexers/electrum_blocking.rs deleted file mode 100644 index a8faa0fc..00000000 --- a/src/indexers/electrum_blocking.rs +++ /dev/null @@ -1,160 +0,0 @@ -// RGB smart contracts for Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2024 by -// Zoe Faltibà -// Rewritten in 2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::iter; -use std::num::NonZeroU32; - -use bp::ConsensusDecode; -use bpstd::{Tx, Txid}; -use electrum::{Client, ElectrumApi, Param}; -pub use electrum::{Config, ConfigBuilder, Error, Socks5Config}; -use rgbstd::vm::WitnessPos; -use rgbstd::ChainNet; - -use super::RgbResolver; -use crate::vm::WitnessOrd; - -macro_rules! check { - ($e:expr) => { - $e.map_err(|e| e.to_string())? - }; -} - -impl RgbResolver for Client { - fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), String> { - // check the electrum server is for the correct network - let block_hash = check!(self.block_header(0)).block_hash(); - if chain_net.genesis_block_hash() != block_hash { - return Err(s!("resolver is for a network different from the wallet's one")); - } - // check the electrum server has the required functionality (verbose - // transactions) - let txid = match chain_net { - ChainNet::BitcoinMainnet => { - "33e794d097969002ee05d336686fc03c9e15a597c1b9827669460fac98799036" - } - ChainNet::BitcoinTestnet3 => { - "5e6560fd518aadbed67ee4a55bdc09f19e619544f5511e9343ebba66d2f62653" - } - ChainNet::BitcoinTestnet4 => { - "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e" - } - ChainNet::BitcoinSignet => { - "8153034f45e695453250a8fb7225a5e545144071d8ed7b0d3211efa1f3c92ad8" - } - ChainNet::BitcoinRegtest => { - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" - } - _ => return Err(s!("only bitcoin is supported")), - }; - if let Err(e) = self.raw_call("blockchain.transaction.get", vec![ - Param::String(txid.to_string()), - Param::Bool(true), - ]) { - if !e - .to_string() - .contains("genesis block coinbase is not considered an ordinary transaction") - { - return Err(s!( - "verbose transactions are unsupported by the provided electrum service" - )); - } - } - Ok(()) - } - - fn resolve_pub_witness_ord(&self, txid: Txid) -> Result { - // We get the height of the tip of blockchain - let header = check!(self.block_headers_subscribe()); - - // Now we get and parse transaction information to get the number of - // confirmations - let tx_details = match self.raw_call("blockchain.transaction.get", vec![ - Param::String(txid.to_string()), - Param::Bool(true), - ]) { - Err(e) - if e.to_string() - .contains("No such mempool or blockchain transaction") => - { - return Ok(WitnessOrd::Archived); - } - Err(e) => return Err(e.to_string()), - Ok(v) => v, - }; - let forward = iter::from_fn(|| self.block_headers_pop().ok().flatten()).count() as isize; - - let Some(confirmations) = tx_details.get("confirmations") else { - return Ok(WitnessOrd::Tentative); - }; - let confirmations = check!(confirmations - .as_u64() - .and_then(|x| u32::try_from(x).ok()) - .ok_or(Error::InvalidResponse(tx_details.clone()))); - if confirmations == 0 { - return Ok(WitnessOrd::Tentative); - } - let block_time = check!(tx_details - .get("blocktime") - .and_then(|v| v.as_i64()) - .ok_or(Error::InvalidResponse(tx_details.clone()))); - - let tip_height = u32::try_from(header.height).map_err(|_| s!("impossible height value"))?; - let height: isize = (tip_height - confirmations) as isize; - const SAFETY_MARGIN: isize = 1; - // first check from expected min to max height - let get_merkle_res = (1..=forward + 1) - // we need this under assumption that electrum was lying due to "DB desynchronization" - // since this have a very low probability we do that after everything else - .chain((1..=SAFETY_MARGIN).flat_map(|i| [i + forward + 1, 1 - i])) - .find_map(|offset| self.transaction_get_merkle(&txid, (height + offset) as usize).ok()) - .ok_or_else(|| s!("transaction can't be located in the blockchain"))?; - - let tx_height = u32::try_from(get_merkle_res.block_height) - .map_err(|_| s!("impossible height value"))?; - - let height = - check!(NonZeroU32::new(tx_height).ok_or(Error::InvalidResponse(tx_details.clone()))); - let pos = check!(WitnessPos::bitcoin(height, block_time) - .ok_or(Error::InvalidResponse(tx_details.clone()))); - - Ok(WitnessOrd::Mined(pos)) - } - - fn resolve_pub_witness(&self, txid: Txid) -> Result, String> { - self.transaction_get_raw(&txid) - .map_err(|e| e.to_string()) - .and_then(|raw_tx| { - Tx::consensus_deserialize(raw_tx) - .map_err(|e| format!("cannot deserialize raw TX - {e}")) - }) - .map(Some) - .or_else(|e| { - if e.contains("No such mempool or blockchain transaction") { - Ok(None) - } else { - Err(e) - } - }) - } -} diff --git a/src/indexers/esplora_blocking.rs b/src/indexers/esplora_blocking.rs deleted file mode 100644 index 1bcaa787..00000000 --- a/src/indexers/esplora_blocking.rs +++ /dev/null @@ -1,70 +0,0 @@ -// RGB smart contracts for Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2023 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2023 LNP/BP Standards Association. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::num::NonZeroU32; - -use bp::Tx; -use bpstd::Txid; -use esplora::BlockingClient; -pub use esplora::{Builder, Config, Error}; -use rgbstd::vm::WitnessPos; -use rgbstd::ChainNet; - -use super::RgbResolver; -use crate::vm::WitnessOrd; - -impl RgbResolver for BlockingClient { - fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), String> { - // check the esplora server is for the correct network - let block_hash = self.block_hash(0)?; - if chain_net.genesis_block_hash() != block_hash { - return Err(s!("resolver is for a network different from the wallet's one")); - } - Ok(()) - } - - fn resolve_pub_witness_ord(&self, txid: Txid) -> Result { - if self.tx(&txid)?.is_none() { - return Ok(WitnessOrd::Archived); - } - let status = self.tx_status(&txid)?; - let ord = match status - .block_height - .and_then(|h| status.block_time.map(|t| (h, t))) - { - Some((h, t)) => { - let height = NonZeroU32::new(h).ok_or(Error::InvalidServerData)?; - WitnessOrd::Mined( - WitnessPos::bitcoin(height, t as i64).ok_or(Error::InvalidServerData)?, - ) - } - None => WitnessOrd::Tentative, - }; - Ok(ord) - } - - fn resolve_pub_witness(&self, txid: Txid) -> Result, String> { - self.tx(&txid).or_else(|e| match e { - Error::TransactionNotFound(_) => Ok(None), - e => Err(e.to_string()), - }) - } -} diff --git a/src/indexers/mempool_blocking.rs b/src/indexers/mempool_blocking.rs deleted file mode 100644 index 0a1ca105..00000000 --- a/src/indexers/mempool_blocking.rs +++ /dev/null @@ -1,132 +0,0 @@ -// RGB smart contracts for Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2023 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2023 LNP/BP Standards Association. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use bp::Tx; -use bpstd::Txid; -use esplora::{BlockingClient, Config, Error}; -use rgbstd::vm::WitnessOrd; -use rgbstd::ChainNet; - -use super::RgbResolver; - -#[derive(Clone, Debug)] -/// Represents a client for interacting with a mempool. -// Currently, this client is wrapping an `esplora::BlockingClient` instance. -// If the mempool service changes in the future and is not compatible with -// esplora::BlockingClient, Only the internal implementation needs to be -// modified -pub struct MemPoolClient { - inner: BlockingClient, -} - -impl MemPoolClient { - /// Creates a new `MemPoolClient` instance. - /// - /// # Arguments - /// - /// * `url` - The URL of the mempool server. - /// * `config` - The configuration for the mempool client. - /// - /// # Returns - /// - /// Returns a `Result` containing the `MemPoolClient` instance if - /// successful, or an `Error` if an error occurred. - #[allow(clippy::result_large_err)] - pub fn new(url: &str, config: Config) -> Result { - let inner = BlockingClient::from_config(url, config)?; - Ok(MemPoolClient { inner }) - } -} - -impl RgbResolver for MemPoolClient { - fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), String> { - self.inner.check_chain_net(chain_net) - } - - fn resolve_pub_witness_ord(&self, txid: Txid) -> Result { - self.inner.resolve_pub_witness_ord(txid) - } - - fn resolve_pub_witness(&self, txid: Txid) -> Result, String> { - self.inner.resolve_pub_witness(txid) - } -} - -#[cfg(test)] -mod test { - use esplora::Config; - #[test] - fn test_mempool_client_mainnet_tx() { - let client = super::MemPoolClient::new("https://mempool.space/api", Config::default()) - .expect("Failed to create client"); - let txid = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" - .parse() - .unwrap(); - let status = client.inner.tx_status(&txid).unwrap(); - assert_eq!(status.block_height, Some(0)); - assert_eq!(status.block_time, Some(1231006505)); - } - - #[test] - fn test_mempool_client_testnet_tx() { - let client = - super::MemPoolClient::new("https://mempool.space/testnet/api", Config::default()) - .expect("Failed to create client"); - - let txid = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" - .parse() - .unwrap(); - let status = client.inner.tx_status(&txid).unwrap(); - assert_eq!(status.block_height, Some(0)); - assert_eq!(status.block_time, Some(1296688602)); - } - - #[test] - fn test_mempool_client_testnet4_tx() { - let client = - super::MemPoolClient::new("https://mempool.space/testnet4/api", Config::default()) - .expect("Failed to create client"); - let txid = "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e" - .parse() - .unwrap(); - let status = client.inner.tx_status(&txid).unwrap(); - assert_eq!(status.block_height, Some(0)); - assert_eq!(status.block_time, Some(1714777860)); - } - - #[test] - fn test_mempool_client_testnet4_tx_detail() { - let client = - super::MemPoolClient::new("https://mempool.space/testnet4/api", Config::default()) - .expect("Failed to create client"); - let txid = "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e" - .parse() - .unwrap(); - let tx = client - .inner - .tx(&txid) - .expect("Failed to get tx") - .expect("Tx not found"); - assert!(tx.inputs.len() > 0); - assert!(tx.outputs.len() > 0); - assert_eq!(tx.outputs[0].value, 5_000_000_000); - } -} diff --git a/src/indexers/mod.rs b/src/indexers/mod.rs deleted file mode 100644 index 45663205..00000000 --- a/src/indexers/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -// RGB smart contracts for Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2023 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2023 LNP/BP Standards Association. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod any; -#[cfg(feature = "esplora_blocking")] -pub mod esplora_blocking; -#[cfg(feature = "electrum_blocking")] -pub mod electrum_blocking; - -#[cfg(feature = "mempool_blocking")] -pub mod mempool_blocking; - -pub use any::{AnyResolver, RgbResolver}; diff --git a/src/lib.rs b/src/lib.rs index 0f10d7b1..c585f5ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,23 +26,26 @@ extern crate amplify; extern crate serde_crate as serde; mod descriptor; -mod indexers; mod filters; pub mod pay; mod errors; mod wallet; -pub use descriptor::{DescriptorRgb, RgbDescr, RgbKeychain, TapTweakAlreadyAssigned, TapretKey}; +pub use descriptor::{DescriptorRgb, RgbDescr, RgbKeychain, TapretKey}; pub use errors::{CompletionError, CompositionError, PayError, WalletError}; pub use pay::{TransferParams, WalletProvider}; pub use rgbstd::*; pub mod resolvers { use bp::Tx; + #[cfg(any( + feature = "electrum_blocking", + feature = "esplora_blocking", + feature = "mempool_blocking" + ))] + pub use rgbstd::indexers::*; + pub use rgbstd::indexers::{AnyResolver, RgbResolver}; use rgbstd::ChainNet; - #[cfg(any(feature = "electrum_blocking", feature = "esplora_blocking"))] - pub use super::indexers::*; - pub use super::indexers::{AnyResolver, RgbResolver}; use super::validation::{ResolveWitness, WitnessResolverError}; use super::vm::WitnessOrd; use super::Txid; diff --git a/src/pay.rs b/src/pay.rs index a3a14d4c..395dd225 100644 --- a/src/pay.rs +++ b/src/pay.rs @@ -19,30 +19,38 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; +use std::convert::Infallible; use std::marker::PhantomData; -use bp::dbc::tapret::TapretProof; +use amplify::confinement::{Confined, U24}; +use bp::dbc::tapret::{TapretCommitment, TapretProof}; +use bp::dbc::Proof; use bp::seals::txout::{CloseMethod, ExplicitSeal}; +use bp::secp256k1::rand; use bp::{Outpoint, Sats, ScriptPubkey, Tx, Vout}; -use bpstd::{psbt, Address}; +use bpstd::{psbt, Address, IdxBase, NormalIndex, Terminal}; use bpwallet::{Layer2, Layer2Tx, NoLayer2, TxRow, Wallet, WalletDescr}; +use chrono::Utc; +use commit_verify::mpc::{Message, ProtocolId}; use psrgbt::{ Beneficiary as BpBeneficiary, Psbt, PsbtConstructor, PsbtMeta, RgbExt, RgbPsbt, TapretKeyError, TxParams, }; -use rgbstd::containers::{AnchorSet, Transfer}; -use rgbstd::interface::AssignmentsFilter; +use rgbstd::containers::{Batch, BuilderSeal, IndexedConsignment, Transfer, TransitionInfo}; +use rgbstd::contract::{AllocatedState, AssignmentsFilter, BuilderError}; use rgbstd::invoice::{Amount, Beneficiary, InvoiceState, RgbInvoice}; -use rgbstd::persistence::{IndexProvider, StashProvider, StateProvider, Stock}; -use rgbstd::validation::ResolveWitness; -use rgbstd::{ChainNet, ContractId, DataState}; +use rgbstd::persistence::{IndexProvider, StashInconsistency, StashProvider, StateProvider, Stock}; +use rgbstd::validation::{ConsignmentApi, DbcProof, ResolveWitness}; +use rgbstd::{ + AssignmentType, ChainNet, ContractId, GraphSeal, Operation, Opout, OutputSeal, RevealedData, +}; use crate::invoice::NonFungible; use crate::validation::WitnessResolverError; use crate::vm::WitnessOrd; use crate::{ - CompletionError, CompositionError, DescriptorRgb, PayError, RgbKeychain, Txid, + CompletionError, CompositionError, DescriptorRgb, PayError, RgbKeychain, Txid, WalletError, WalletOutpointsFilter, WalletUnspentFilter, WalletWitnessFilter, }; @@ -112,8 +120,12 @@ where Self::Descr: DescriptorRgb fn txos(&self) -> impl Iterator; fn txids(&self) -> impl Iterator; fn history(&self) -> impl Iterator> + '_; - - // TODO: Add method `color` to add RGB information to an already existing PSBT + fn add_tapret_tweak( + &mut self, + terminal: Terminal, + tapret_commitment: TapretCommitment, + ) -> Result<(), Infallible>; + fn try_add_tapret_tweak(&mut self, transfer: Transfer, txid: &Txid) -> Result<(), WalletError>; #[allow(clippy::result_large_err)] fn pay( @@ -138,29 +150,66 @@ where Self::Descr: DescriptorRgb invoice: &RgbInvoice, mut params: TransferParams, ) -> Result<(Psbt, PsbtMeta), CompositionError> { + let close_method = self.descriptor().close_method(); + let contract_id = invoice.contract.ok_or(CompositionError::NoContract)?; + let contract = stock + .contract_data(contract_id) + .map_err(|e| e.to_string())?; - let close_method = self.descriptor().close_method(); + if let Some(invoice_schema) = invoice.schema { + if invoice_schema != contract.schema.schema_id() { + return Err(CompositionError::InvalidSchema); + } + } - let iface_name = invoice.iface.clone().ok_or(CompositionError::NoIface)?; - let iface = stock.iface(iface_name.clone()).map_err(|e| e.to_string())?; - let operation = invoice - .operation - .as_ref() - .or(iface.default_operation.as_ref()) - .ok_or(CompositionError::NoOperation)?; + let contract_genesis = stock + .as_stash_provider() + .genesis(contract_id) + .map_err(|_| CompositionError::UnknownContract)?; + let contract_chain_net = contract_genesis.chain_net; + let invoice_chain_net = invoice.chain_network(); + if contract_chain_net != invoice_chain_net { + return Err(CompositionError::InvoiceBeneficiaryWrongChainNet( + invoice_chain_net, + contract_chain_net, + )); + } + + if let Some(expiry) = invoice.expiry { + if expiry < Utc::now().timestamp() { + return Err(CompositionError::InvoiceExpired); + } + } + + let Some(ref assignment_state) = invoice.assignment_state else { + return Err(CompositionError::NoAssignmentState); + }; - let assignment_name = invoice - .assignment + let invoice_assignment_type = invoice + .assignment_name + .as_ref() + .map(|n| contract.schema.assignment_type(n.clone())); + let assignment_type = invoice_assignment_type .as_ref() .or_else(|| { - iface - .transitions - .get(operation) - .and_then(|t| t.default_assignment.as_ref()) + let assignment_types = contract + .schema + .assignment_types_for_state(assignment_state.clone().into()); + if assignment_types.len() == 1 { + Some(assignment_types[0]) + } else { + contract + .schema + .default_assignment + .as_ref() + .filter(|&assignment| assignment_types.contains(&assignment)) + } }) - .cloned() - .ok_or(CompositionError::NoAssignment)?; + .ok_or(CompositionError::NoAssignmentType)?; + let transition_type = contract + .schema + .default_transition_for_assignment(assignment_type); let filter = ContractOutpointsFilter { contract_id, @@ -169,13 +218,10 @@ where Self::Descr: DescriptorRgb _key_phantom: PhantomData, _layer2_phantom: PhantomData, }; - let contract = stock - .contract_iface(contract_id, iface_name) - .map_err(|e| e.to_string())?; - let prev_outputs = match invoice.owned_state { + let prev_outputs = match assignment_state { InvoiceState::Amount(amount) => { let state: BTreeMap<_, Vec> = contract - .fungible(assignment_name, &filter)? + .fungible_raw(*assignment_type, &filter)? .fold(bmap![], |mut set, a| { set.entry(a.seal).or_default().push(a.state); set @@ -190,7 +236,7 @@ where Self::Descr: DescriptorRgb .iter() .rev() .take_while(|(val, _, _)| { - if sum >= amount { + if sum >= *amount { false } else { sum += *val; @@ -199,63 +245,83 @@ where Self::Descr: DescriptorRgb }) .map(|(_, seal, _)| *seal) .collect::>(); - if sum < amount { + if sum < *amount { bset![] } else { selection } } - InvoiceState::Data(NonFungible::RGB21(allocation)) => { - let data_state = DataState::from(allocation); + InvoiceState::Data(NonFungible::FractionedToken(allocation)) => { + let data_state = RevealedData::from(*allocation); contract - .data(assignment_name, &filter)? + .data_raw(*assignment_type, &filter)? .filter(|x| x.state == data_state) .map(|x| x.seal) .collect::>() } - _ => return Err(CompositionError::Unsupported), - }; - let beneficiaries = match invoice.beneficiary.into_inner() { - Beneficiary::BlindedSeal(_) => vec![], - Beneficiary::WitnessVout(pay2vout) => { - vec![BpBeneficiary::new( - Address::new(*pay2vout, invoice.address_network()), - params.min_amount, - )] - } + InvoiceState::Void => contract + .rights_raw(*assignment_type, &filter)? + .map(|x| x.seal) + .collect::>(), }; if prev_outputs.is_empty() { return Err(CompositionError::InsufficientState); } let prev_outpoints = prev_outputs.iter().map(|o| Outpoint::new(o.txid, o.vout)); params.tx.change_keychain = RgbKeychain::for_method(close_method).into(); + + let (beneficiaries, beneficiary_script) = match invoice.beneficiary.into_inner() { + Beneficiary::BlindedSeal(_) => (vec![], None), + Beneficiary::WitnessVout(pay2vout, _) => ( + vec![BpBeneficiary::new( + Address::new(*pay2vout, invoice.address_network()), + params.min_amount, + )], + Some(pay2vout.script_pubkey()), + ), + }; + let (mut psbt, mut meta) = self.construct_psbt(prev_outpoints, &beneficiaries, params.tx)?; - let beneficiary_script = - if let Beneficiary::WitnessVout(pay2vout) = invoice.beneficiary.into_inner() { - Some(pay2vout.script_pubkey()) - } else { - None - }; - psbt.outputs_mut() - .find(|o| o.script.is_p2tr() && Some(&o.script) != beneficiary_script.as_ref()) - .map(|o| o.set_tapret_host().expect("just created")); - // TODO: Add descriptor id to the tapret host data - let change_script = meta .change_vout .and_then(|vout| psbt.output(vout.to_usize())) .map(|output| output.script.clone()); - if close_method == CloseMethod::OpretFirst { - let output = psbt.construct_output_expect(ScriptPubkey::op_return(&[]), Sats::ZERO); - output.set_opret_host().expect("just created"); - psbt.sort_outputs_by(|output| !output.is_opret_host()) - .expect("PSBT must be modifiable at this stage"); - } else { - psbt.sort_outputs_by(|output| !output.is_tapret_host()) - .expect("PSBT must be modifiable at this stage"); - }; + + match close_method { + CloseMethod::TapretFirst => { + let tap_out_script = if let Some(change_script) = change_script.clone() { + psbt.set_rgb_tapret_host_on_change(); + change_script + } else { + match invoice.beneficiary.into_inner() { + Beneficiary::WitnessVout(_, Some(ikey)) => { + let beneficiary_script = beneficiary_script.unwrap(); + psbt.outputs_mut() + .find(|o| o.script == beneficiary_script) + .unwrap() + .tap_internal_key = Some(ikey); + beneficiary_script + } + _ => return Err(CompositionError::NoOutputForTapretCommitment), + } + }; + psbt.outputs_mut() + .find(|o| o.script.is_p2tr() && o.script == tap_out_script) + .map(|o| o.set_tapret_host().expect("just created")); + // TODO: Add descriptor id to the tapret host data + psbt.sort_outputs_by(|output| !output.is_tapret_host()) + .expect("PSBT must be modifiable at this stage"); + } + CloseMethod::OpretFirst => { + let output = psbt.construct_output_expect(ScriptPubkey::op_return(&[]), Sats::ZERO); + output.set_opret_host().expect("just created"); + psbt.sort_outputs_by(|output| !output.is_opret_host()) + .expect("PSBT must be modifiable at this stage"); + } + } + if let Some(ref change_script) = change_script { for output in psbt.outputs() { if output.script == *change_script { @@ -266,7 +332,7 @@ where Self::Descr: DescriptorRgb } let beneficiary_vout = match invoice.beneficiary.into_inner() { - Beneficiary::WitnessVout(pay2vout) => { + Beneficiary::WitnessVout(pay2vout, _) => { let s = (*pay2vout).script_pubkey(); let vout = psbt .outputs() @@ -278,10 +344,160 @@ where Self::Descr: DescriptorRgb } Beneficiary::BlindedSeal(_) => None, }; - let batch = stock - .compose(invoice, prev_outputs, beneficiary_vout, |_, _, _| meta.change_vout) + + #[allow(clippy::type_complexity)] + let output_for_assignment = + |assignment_type: AssignmentType| -> Result, CompositionError> { + let vout = meta + .change_vout + .ok_or(CompositionError::NoExtraOrChange(assignment_type))?; + let seal = GraphSeal::with_blinded_vout(vout, rand::random()); + Ok(BuilderSeal::Revealed(seal)) + }; + + let builder_seal = match (invoice.beneficiary.into_inner(), beneficiary_vout) { + (Beneficiary::BlindedSeal(seal), None) => BuilderSeal::Concealed(seal), + (Beneficiary::BlindedSeal(_), Some(_)) => { + return Err(CompositionError::BeneficiaryVout); + } + (Beneficiary::WitnessVout(_, _), Some(vout)) => { + let seal = GraphSeal::with_blinded_vout(vout, rand::random()); + BuilderSeal::Revealed(seal) + } + (Beneficiary::WitnessVout(_, _), None) => { + return Err(CompositionError::NoBeneficiaryOutput); + } + }; + + let mut main_builder = stock + .transition_builder_raw(contract_id, transition_type) .map_err(|e| e.to_string())?; + let prev_outputs = prev_outputs.into_iter().collect::>(); + let mut main_inputs = Vec::::new(); + let mut sum_inputs = Amount::ZERO; + let mut data_inputs = vec![]; + for (output, list) in stock + .contract_assignments_for(contract_id, prev_outputs.iter().copied()) + .map_err(|e| e.to_string())? + { + main_inputs.push(output); + for (opout, state) in list { + main_builder = main_builder.add_input(opout, state.clone())?; + if opout.ty != *assignment_type { + let seal = output_for_assignment(opout.ty)?; + main_builder = main_builder.add_owned_state_raw(opout.ty, seal, state)?; + } else if let AllocatedState::Amount(value) = state { + sum_inputs += value.into(); + } else if let AllocatedState::Data(value) = state { + data_inputs.push(value); + } + } + } + + // Add payments to beneficiary and change + match assignment_state.clone() { + InvoiceState::Amount(amt) => { + // Pay beneficiary + if sum_inputs < amt { + return Err(CompositionError::InsufficientState); + } + + if amt > Amount::ZERO { + main_builder = + main_builder.add_fungible_state_raw(*assignment_type, builder_seal, amt)?; + } + + // Pay change + if sum_inputs > amt { + let change_seal = output_for_assignment(*assignment_type)?; + main_builder = main_builder.add_fungible_state_raw( + *assignment_type, + change_seal, + sum_inputs - amt, + )?; + } + } + InvoiceState::Data(data) => match data { + NonFungible::FractionedToken(allocation) => { + let lookup_state = RevealedData::from(allocation); + if !data_inputs.into_iter().any(|x| x == lookup_state) { + return Err(CompositionError::InsufficientState); + } + + main_builder = + main_builder.add_data_raw(*assignment_type, builder_seal, lookup_state)?; + } + }, + InvoiceState::Void => { + main_builder = main_builder.add_rights_raw(*assignment_type, builder_seal)?; + } + } + + // 3. Prepare other transitions + // Enumerate state + let mut extra_state = + HashMap::>>::new(); + for id in stock + .contracts_assigning(prev_outputs.iter().copied()) + .map_err(|e| e.to_string())? + { + // Skip current contract + if id == contract_id { + continue; + } + let state = stock + .contract_assignments_for(id, prev_outputs.iter().copied()) + .map_err(|e| e.to_string())?; + let entry = extra_state.entry(id).or_default(); + for (seal, assigns) in state { + entry.entry(seal).or_default().extend(assigns); + } + } + + // Construct transitions for extra state + let mut extras = Confined::, 0, { U24 - 1 }>::with_capacity(extra_state.len()); + for (id, seal_map) in extra_state { + let schema = stock + .as_stash_provider() + .contract_schema(id) + .map_err(|_| BuilderError::Inconsistency(StashInconsistency::ContractAbsent(id)))?; + + for (output, assigns) in seal_map { + for (opout, state) in assigns { + let transition_type = schema.default_transition_for_assignment(&opout.ty); + + let mut extra_builder = stock + .transition_builder_raw(id, transition_type) + .map_err(|e| e.to_string())?; + + let seal = output_for_assignment(opout.ty)?; + extra_builder = extra_builder + .add_input(opout, state.clone())? + .add_owned_state_raw(opout.ty, seal, state)?; + + if !extra_builder.has_inputs() { + continue; + } + let transition = extra_builder.complete_transition()?; + let info = TransitionInfo::new(transition, [output]) + .map_err(|_| CompositionError::TooManyInputs)?; + extras + .push(info) + .map_err(|_| CompositionError::TooManyExtras)?; + } + } + } + + if !main_builder.has_inputs() { + return Err(CompositionError::InsufficientState); + } + + let main = TransitionInfo::new(main_builder.complete_transition()?, main_inputs) + .map_err(|_| CompositionError::TooManyInputs)?; + let mut batch = Batch { main, extras }; + batch.set_priority(u64::MAX); + psbt.set_rgb_close_method(close_method); psbt.complete_construction(); psbt.rgb_embed(batch)?; @@ -297,30 +513,37 @@ where Self::Descr: DescriptorRgb ) -> Result { let contract_id = invoice.contract.ok_or(CompletionError::NoContract)?; - let fascia = psbt.rgb_commit()?; - if matches!(fascia.anchor, AnchorSet::Tapret(_)) { - let output = psbt - .dbc_output::() - .ok_or(TapretKeyError::NotTaprootOutput)?; - let terminal = output - .terminal_derivation() - .ok_or(CompletionError::InconclusiveDerivation)?; - let tapret_commitment = output.tapret_commitment()?; - self.with_descriptor_mut(|descr| { - descr.with_descriptor_mut(|d| d.add_tapret_tweak(terminal, tapret_commitment)) - })?; - } - - let witness_id = psbt.txid(); - let (beneficiary1, beneficiary2) = match invoice.beneficiary.into_inner() { - Beneficiary::WitnessVout(pay2vout) => { + let beneficiary_vout = match invoice.beneficiary.into_inner() { + Beneficiary::WitnessVout(pay2vout, _) => { let s = (*pay2vout).script_pubkey(); let vout = psbt .outputs() .position(|output| output.script == s) .ok_or(CompletionError::NoBeneficiaryOutput)?; - let vout = Vout::from_u32(vout as u32); - let seal = ExplicitSeal::new(Outpoint::new(witness_id, vout)); + Some(Vout::from_u32(vout as u32)) + } + Beneficiary::BlindedSeal(_) => None, + }; + + let fascia = psbt.rgb_commit()?; + if matches!(fascia.seal_witness.dbc_proof.method(), CloseMethod::TapretFirst) { + // save tweak only if tapret commitment is on the bitcoin change + if psbt.rgb_tapret_host_on_change() { + let output = psbt + .dbc_output::() + .ok_or(TapretKeyError::NotTaprootOutput)?; + let terminal = output + .terminal_derivation() + .ok_or(CompletionError::InconclusiveDerivation)?; + let tapret_commitment = output.tapret_commitment()?; + self.add_tapret_tweak(terminal, tapret_commitment)?; + } + } + + let witness_id = psbt.txid(); + let (beneficiary1, beneficiary2) = match invoice.beneficiary.into_inner() { + Beneficiary::WitnessVout(_, _) => { + let seal = ExplicitSeal::new(Outpoint::new(witness_id, beneficiary_vout.unwrap())); (None, vec![seal]) } Beneficiary::BlindedSeal(seal) => (Some(seal), vec![]), @@ -371,4 +594,59 @@ impl, L2: Layer2> WalletProvider for Wallet impl Iterator { self.transactions().keys().copied() } fn history(&self) -> impl Iterator> + '_ { self.history() } + + fn add_tapret_tweak( + &mut self, + terminal: Terminal, + tapret_commitment: TapretCommitment, + ) -> Result<(), Infallible> { + self.with_descriptor_mut(|descr| { + descr.with_descriptor_mut(|d| { + d.add_tapret_tweak(terminal, tapret_commitment); + Ok::<_, Infallible>(()) + }) + }) + } + + fn try_add_tapret_tweak(&mut self, transfer: Transfer, txid: &Txid) -> Result<(), WalletError> { + let indexed_consignment = IndexedConsignment::new(&transfer); + let contract_id = transfer.genesis.contract_id(); + let close_method = self.descriptor().close_method(); + let keychain = RgbKeychain::for_method(close_method); + let last_index = self.next_derivation_index(keychain, false).index() as u16; + let descr = self.descriptor(); + if let Some((idx, tweak)) = transfer + .bundles + .iter() + .find(|bw| bw.witness_id() == *txid) + .and_then(|bw| { + let bundle_id = bw.bundle().bundle_id(); + let (_, anchor) = indexed_consignment.anchor(bundle_id).unwrap(); + if let DbcProof::Tapret(tapret) = anchor.dbc_proof.clone() { + let commitment = anchor + .mpc_proof + .clone() + .convolve(ProtocolId::from(contract_id), Message::from(bundle_id)) + .unwrap(); + let tweak = TapretCommitment::with(commitment, tapret.path_proof.nonce()); + (0..last_index) + .rev() + .map(NormalIndex::normal) + .find(|i| { + descr + .derive(keychain, i) + .any(|ds| ds.to_internal_pk() == Some(tapret.internal_pk)) + }) + .map(|idx| (idx, tweak)) + } else { + None + } + }) + { + self.add_tapret_tweak(Terminal::new(keychain, idx), tweak) + .unwrap(); + return Ok(()); + } + Err(WalletError::NoTweakTerminal) + } } diff --git a/src/wallet.rs b/src/wallet.rs index 172c82b5..72d1d8fc 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -33,12 +33,11 @@ use bpwallet::{Layer2, NoLayer2}; use nonasync::persistence::PersistenceProvider; use psrgbt::{Psbt, PsbtMeta}; use rgbstd::containers::Transfer; -use rgbstd::interface::{ContractOp, IfaceRef}; +use rgbstd::contract::ContractOp; #[cfg(feature = "fs")] use rgbstd::persistence::fs::FsBinStore; use rgbstd::persistence::{ - ContractIfaceError, IndexProvider, MemIndex, MemStash, MemState, StashProvider, StateProvider, - Stock, StockError, + IndexProvider, MemIndex, MemStash, MemState, StashProvider, StateProvider, Stock, StockError, }; use super::{ @@ -124,12 +123,8 @@ where W::Descr: DescriptorRgb pub fn wallet_mut(&mut self) -> &mut W { &mut self.wallet } - pub fn history( - &self, - contract_id: ContractId, - iface: impl Into, - ) -> Result, StockError> { - let contract = self.stock.contract_iface(contract_id, iface.into())?; + pub fn history(&self, contract_id: ContractId) -> Result, StockError> { + let contract = self.stock.contract_data(contract_id)?; let wallet = &self.wallet; Ok(contract.history(wallet.filter_outpoints(), wallet.filter_witnesses())) }