diff --git a/Cargo.lock b/Cargo.lock index 8ad9c47..485a13b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - [[package]] name = "aho-corasick" version = "1.1.3" @@ -40,9 +34,9 @@ dependencies = [ [[package]] name = "amplify" -version = "4.7.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7147b742325842988dd6c793d55f58df3ae36bccf7d9b6e07db10ab035be343d" +checksum = "b2090b9b79b61d4047a307a46de043d0ee5ec406d99a7d652341b96d48ed5567" dependencies = [ "amplify_apfloat", "amplify_derive", @@ -237,11 +231,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95dabc2759e01e2c382968639868a701f384a18890934f9e75d4feb4d6623794" dependencies = [ "amplify", - "base64", + "base64 0.22.1", "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" @@ -292,12 +292,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" -[[package]] -name = "bitcoin-private" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" - [[package]] name = "bitcoin_hashes" version = "0.14.0" @@ -344,14 +338,14 @@ dependencies = [ [[package]] name = "bp-consensus" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54db63118d55e32ea78f8775e98871d442a33e3bdef6419c7964d71b308316c0" +checksum = "40f227ce25d185bc5fc9109ca83dfa8bd0e745f219e320f3da658aaf4fd7e0c5" dependencies = [ "amplify", "chrono", "commit_verify", - "secp256k1 0.30.0", + "secp256k1", "serde", "strict_encoding", "strict_types", @@ -359,9 +353,9 @@ dependencies = [ [[package]] name = "bp-core" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e51a329150531b12243adf51d978490c796a6a20ec76c506b41c8e1226022bc" +checksum = "40c6b213ada98fe5e78a978e67a7044d16d2571edb3f85fcdb4246324ec9514a" dependencies = [ "amplify", "bp-consensus", @@ -378,24 +372,24 @@ dependencies = [ [[package]] name = "bp-dbc" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9286fb448160672148262317f4647ebdcdd4699ed2bd34401f9799d0920cc376" +checksum = "d33d4cc345a595236441fc2b8726ca7eb693947914b278849d1e2c1923dcb314" dependencies = [ "amplify", "base85", "bp-consensus", "commit_verify", - "secp256k1 0.30.0", + "secp256k1", "serde", "strict_encoding", ] [[package]] name = "bp-derive" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "394f8a2c3f4df405aff7269d1727b463e2cf74ec35a077fe7425084cdbdd0448" +checksum = "23ebed0079fc2e75dc238103f0f81fefd2cbbc3120ae55c58fe0aa61dad26ddc" dependencies = [ "amplify", "bp-consensus", @@ -409,43 +403,43 @@ dependencies = [ [[package]] name = "bp-electrum" -version = "0.11.0-beta.9.2" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc58108a622b07755bf4a9468325b76e74f47042b1b493ff30a9059a20c2c34a" +checksum = "43476738e6327bfda9c1d7bcffcdb5f931ad03cbe4dc26fe4087fe505b7d96d2" dependencies = [ "amplify", "bp-std", "byteorder", "libc", "log", - "rustls", + "rustls 0.23.16", "serde", "serde_json", "sha2", - "webpki-roots", + "webpki-roots 0.26.6", "winapi", ] [[package]] name = "bp-esplora" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5b002e82289784e579f130ebdc22aa0b19a7b873620ea1dab16628999ba404d" +checksum = "fea6ad8f3ae73ea99517a9eab934a8abf7a1463e562da47dc124b4cd1b16692f" dependencies = [ "amplify", "bp-std", "log", + "minreq", "serde", "serde_with", "sha2", - "ureq", ] [[package]] name = "bp-invoice" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfe7be7b2d740de57e895f2ac93b305bbd67a2a0914dac424f8569bb9981679" +checksum = "fd6955d67eec75b22532edb859f1f4d7d4ba4af1db304abc511530f4e1a827b7" dependencies = [ "amplify", "bech32", @@ -456,9 +450,9 @@ dependencies = [ [[package]] name = "bp-seals" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9873cfe420f4ce5cc539c394c75df0669cdbe2c23eed1930dffe024cb0f13a57" +checksum = "6a7a009fbf7e71be7ab5f43e032c69927f58cd7f59a6a822af64f84d3e8d41c5" dependencies = [ "amplify", "baid64", @@ -473,9 +467,9 @@ dependencies = [ [[package]] name = "bp-std" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e23c585b49b6d3112b0ea1a2d2e143f493fd0ecbb3bb11bbbe41c69b63a4411c" +checksum = "f78d36be2d9ef2f70821c8d73f9f58739d0057f7cba9aa30b05d64247bd8554d" dependencies = [ "amplify", "bp-consensus", @@ -485,19 +479,19 @@ dependencies = [ "descriptors", "getrandom", "psbt", - "secp256k1 0.30.0", + "secp256k1", "serde", "wasm-bindgen", ] [[package]] name = "bp-wallet" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b442fa1f317e9eec6bf52ef93ecdf21b9ab28245395850d466d90664ee4532" +checksum = "5a1ea4b3bca45bfc61613847bd3c2a03c650e4c376c81e584a7e83cd33edbc4f" dependencies = [ "amplify", - "base64", + "base64 0.22.1", "bp-electrum", "bp-esplora", "bp-std", @@ -648,9 +642,9 @@ dependencies = [ [[package]] name = "commit_encoding_derive" -version = "0.11.0-beta.8" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea07c5ad73a637276dc4f8a957f8285764018d45bdefef35eb9137f32d0e3c81" +checksum = "dc09678c15e9280cc6eaf29bf437a2cf18fadedd8bf78c369b8ac15fa217dbe5" dependencies = [ "amplify", "amplify_syn", @@ -661,9 +655,9 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.11.0-beta.9" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf08c4941e147937551f6a3d370552d67f98cf72c9eb18948142596beadd31e" +checksum = "0fcf5f557e112c684f2458f20c66bab865c01cab56d6a318f64243cba9b163a7" dependencies = [ "amplify", "commit_encoding_derive", @@ -707,15 +701,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - [[package]] name = "crunchy" version = "0.2.2" @@ -779,9 +764,9 @@ dependencies = [ [[package]] name = "descriptors" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49798157ca640745a3c898714b5805c28482295de8819cb7b2c530b8f9246df1" +checksum = "4bb1e86bc1bbf96aa464ae3f8bbec92afc83da40f1470109ce4207d708773d06" dependencies = [ "amplify", "bp-derive", @@ -878,16 +863,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a35a73237400bde66c82e38387343f90d7182a2f2f22729e096a2abd57d75db9" -[[package]] -name = "flate2" -version = "1.0.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fluent-uri" version = "0.1.4" @@ -903,15 +878,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - [[package]] name = "fs_extra" version = "1.3.0" @@ -1043,16 +1009,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -1193,12 +1149,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "miniz_oxide" -version = "0.8.0" +name = "minreq" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "da0c420feb01b9fb5061f8c8f452534361dd783756dcf38ec45191ce55e7a161" dependencies = [ - "adler2", + "base64 0.12.3", + "log", + "once_cell", + "rustls 0.21.12", + "rustls-webpki 0.101.7", + "serde", + "serde_json", + "webpki-roots 0.25.4", ] [[package]] @@ -1308,12 +1271,12 @@ dependencies = [ [[package]] name = "psbt" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d36b72ab550141a04a368c25611bf04c87178b65d3be5165529e0b010ee551b" +checksum = "a60fcac15e3bd83cbca0388d70ac696f066790e992a5ceb230a04317ae8b991e" dependencies = [ "amplify", - "base64", + "base64 0.22.1", "bp-core", "bp-derive", "chrono", @@ -1405,9 +1368,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rgb-core" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cf48c4e395882c5228cd788a78e04674c94f7c177d82afdd87def8619f5dff8" +checksum = "3ae7debf4fc13bbf2d217f71d29a0233fddf5fc5b148ded64175df36c3635029" dependencies = [ "aluvm", "amplify", @@ -1417,7 +1380,7 @@ dependencies = [ "commit_verify", "getrandom", "mime", - "secp256k1-zkp", + "secp256k1", "serde", "single_use_seals", "strict_encoding", @@ -1427,9 +1390,9 @@ dependencies = [ [[package]] name = "rgb-invoice" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac03ef76ffe2f4f3ad51b77f02bfd265c347f088d3acac3814cf8a910a86d990" +checksum = "d713f88dce2b3ca159150fb9617ed4af2a2b4a785437138e74f74598acd05adb" dependencies = [ "amplify", "baid64", @@ -1492,9 +1455,9 @@ dependencies = [ [[package]] name = "rgb-std" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6797d4950dbb803382132ff4ddc3523d49e3de21a49311bf6367fe4854e814" +checksum = "d98b5d547e950f138f26c1eeb6ec98d53bc7adb8b96e311e9f1b7ac08252e050" dependencies = [ "aluvm", "amplify", @@ -1581,6 +1544,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.16" @@ -1590,9 +1565,8 @@ dependencies = [ "aws-lc-rs", "log", "once_cell", - "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -1603,6 +1577,16 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.102.8" @@ -1637,14 +1621,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] -name = "secp256k1" -version = "0.29.1" +name = "sct" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "rand", - "secp256k1-sys", - "serde", + "ring", + "untrusted", ] [[package]] @@ -1668,29 +1651,6 @@ dependencies = [ "cc", ] -[[package]] -name = "secp256k1-zkp" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a44aed3002b5ae975f8624c5df3a949cfbf00479e18778b6058fcd213b76e3" -dependencies = [ - "bitcoin-private", - "rand", - "secp256k1 0.29.1", - "secp256k1-zkp-sys", - "serde", -] - -[[package]] -name = "secp256k1-zkp-sys" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57f08b2d0b143a22e07f798ae4f0ab20d5590d7c68e0d090f2088a48a21d1654" -dependencies = [ - "cc", - "secp256k1-sys", -] - [[package]] name = "serde" version = "1.0.214" @@ -1748,7 +1708,7 @@ version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", @@ -1813,24 +1773,13 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" -version = "0.11.0-beta.9" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec071f3b3153217f1cb2bca5ba7ac87eeafc446cb35a5c0643dec33495a37244" +checksum = "b01aad2d785dc858c4f652d1e18d0c815cd10aa8f15ac7accd2b12b894d7c367" dependencies = [ "amplify_derive", ] -[[package]] -name = "socks" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b" -dependencies = [ - "byteorder", - "libc", - "winapi", -] - [[package]] name = "spin" version = "0.9.8" @@ -1979,21 +1928,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "toml" version = "0.8.19" @@ -2034,27 +1968,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - [[package]] name = "unicode-ident" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -2067,36 +1986,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "ureq" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" -dependencies = [ - "base64", - "flate2", - "log", - "once_cell", - "rustls", - "rustls-pki-types", - "serde", - "serde_json", - "socks", - "url", - "webpki-roots", -] - -[[package]] -name = "url" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - [[package]] name = "utf8parse" version = "0.2.2" @@ -2238,6 +2127,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "webpki-roots" version = "0.26.6" diff --git a/Cargo.toml b/Cargo.toml index fa7e1fe..12e808e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,12 +27,12 @@ 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.0-beta.9" -bp-std = { version = "0.11.0-beta.9", features = ["client-side-validation"] } -bp-electrum = "0.11.0-beta.9" -bp-esplora = { version = "0.11.0-beta.9", default-features = false } -bp-wallet = { version = "0.11.0-beta.9" } -rgb-std = { version = "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.0-beta.9", path = "psbt" } indexmap = "2.4.0" chrono = "0.4.38" @@ -90,7 +90,7 @@ 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"] +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"] diff --git a/cli/README.md b/cli/README.md index af0b599..64b3747 100644 --- a/cli/README.md +++ b/cli/README.md @@ -38,7 +38,7 @@ from source ``` $ git clone $ cd rgb/cli -$ cargo install --path --all-features . +$ cargo install --all-features --path . ``` ## Data Directory @@ -274,14 +274,14 @@ globals: assignments: assetOwner: - seal: tapret1st:fb9ae7ae4b70a27e7fdfdefac91b37967b549d65007dbf25470b0817a2ae810a:1 + seal: fb9ae7ae4b70a27e7fdfdefac91b37967b549d65007dbf25470b0817a2ae810a:1 amount: 100000000 # this is 1 million (we have two digits for cents) ``` -Here, we observe a seal value in the form of `closing_method:txid:vout` and here closing method is `tapret1st` (can also -be `opret1st`). This hash, in reality, represents the txid of the previously created PSBT. And `txid:vout` is the -outpoint of a valid UTXO. +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 +the outpoint of a valid UTXO. Compile the contract: diff --git a/cli/src/args.rs b/cli/src/args.rs index 4614f5d..b047729 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -26,12 +26,12 @@ use std::io::ErrorKind; use std::ops::{Deref, DerefMut}; use std::path::PathBuf; -use bpstd::{Wpkh, XpubDerivable}; +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::{RgbDescr, RgbWallet, TapretKey, WalletError}; +use rgb::{ChainNet, RgbDescr, RgbWallet, TapretKey, WalletError}; use rgbstd::persistence::fs::FsBinStore; use strict_types::encoding::{DecodeError, DeserializeError}; @@ -131,7 +131,7 @@ impl RgbArgs { let resolver = self.resolver()?; let from_height = self.from_height.unwrap_or(1); eprint!("Updating witness information starting from height {from_height} ... "); - let res = stock.update_witnesses(resolver, from_height)?; + let res = stock.update_witnesses(resolver, from_height, vec![])?; eprint!("{} transactions were checked and updated", res.succeeded); if res.failed.is_empty() { eprintln!(); @@ -189,7 +189,17 @@ impl RgbArgs { --esplora --mempool or --electrum argument")), } .map_err(WalletError::Resolver)?; - resolver.check(self.general.network)?; + resolver.check_chain_net(self.chain_net())?; Ok(resolver) } + + pub fn chain_net(&self) -> ChainNet { + match self.general.network { + Network::Mainnet => ChainNet::BitcoinMainnet, + Network::Regtest => ChainNet::BitcoinRegtest, + Network::Signet => ChainNet::BitcoinSignet, + Network::Testnet3 => ChainNet::BitcoinTestnet3, + Network::Testnet4 => ChainNet::BitcoinTestnet4, + } + } } diff --git a/cli/src/command.rs b/cli/src/command.rs index f14b5c2..6504828 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -29,7 +29,7 @@ use amplify::confinement::{SmallOrdMap, TinyOrdMap, TinyOrdSet, U16 as MAX16}; use baid64::DisplayBaid64; use bpstd::psbt::{Psbt, PsbtVer}; use bpstd::seals::SecretSeal; -use bpstd::{Sats, XpubDerivable}; +use bpstd::{Sats, Txid, XpubDerivable}; use bpwallet::cli::{BpCommand, Config, Exec}; use bpwallet::Wallet; use rgb::containers::{ @@ -44,9 +44,9 @@ use rgb::schema::SchemaId; use rgb::validation::Validity; use rgb::vm::{RgbIsa, WitnessOrd}; use rgb::{ - Allocation, BundleId, ContractId, DescriptorRgb, GenesisSeal, GraphSeal, Identity, OpId, - OutputSeal, OwnedFraction, RgbDescr, RgbKeychain, RgbWallet, StateType, TokenIndex, - TransferParams, WalletError, WalletProvider, XChain, XOutpoint, XWitnessId, + Allocation, BundleId, ContractId, GenesisSeal, GraphSeal, Identity, OpId, Outpoint, OutputSeal, + OwnedFraction, RgbDescr, RgbKeychain, RgbWallet, StateType, TokenIndex, TransferParams, + WalletError, WalletProvider, }; use rgbstd::interface::{AllocatedState, ContractIface, OwnedIface}; use rgbstd::persistence::{MemContractState, StockError}; @@ -476,12 +476,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.general.network.is_testnet()) - .map_err(|(status, _)| { + let contract = contract.validate(&resolver, self.chain_net()).map_err( + |(status, _)| { eprintln!("failure"); status.to_string() - })?; + }, + )?; eprintln!("success"); stock.import_contract(contract, &resolver)?; eprintln!("Consignment is imported"); @@ -574,11 +574,11 @@ impl Exec for RgbArgs { WalletAll(&'w RgbWallet>), NoWallet, } - impl<'w> AssignmentsFilter for Filter<'w> { + impl AssignmentsFilter for Filter<'_> { fn should_include( &self, - outpoint: impl Into, - id: Option, + outpoint: impl Into, + id: Option, ) -> bool { match self { Filter::Wallet(wallet) => wallet @@ -589,12 +589,8 @@ impl Exec for RgbArgs { } } } - impl<'w> Filter<'w> { - fn comment(&self, outpoint: XOutpoint) -> &'static str { - let outpoint = outpoint - .into_bp() - .into_bitcoin() - .expect("liquid is not yet supported"); + impl Filter<'_> { + fn comment(&self, outpoint: Outpoint) -> &'static str { match self { Filter::Wallet(rgb) if rgb.wallet().is_unspent(outpoint) => "", Filter::WalletAll(rgb) if rgb.wallet().is_unspent(outpoint) => { @@ -704,7 +700,12 @@ impl Exec for RgbArgs { )) })?; - let mut builder = stock.contract_builder(issuer.clone(), *schema_id, iface_id)?; + let mut builder = stock.contract_builder( + issuer.clone(), + *schema_id, + iface_id, + self.chain_net(), + )?; let types = builder.type_system().clone(); if let Some(globals) = code.get("globals") { @@ -732,6 +733,7 @@ impl Exec for RgbArgs { .typify(val, sem_id) .expect("global type doesn't match type definition"); + #[allow(deprecated)] let serialized = types .strict_serialize_type::(&typed_val) .expect("internal error"); @@ -771,7 +773,7 @@ impl Exec for RgbArgs { .as_str() .expect("seal must be a string"); let seal = OutputSeal::from_str(seal).expect("invalid seal definition"); - let seal = GenesisSeal::new_random(seal.method, seal.txid, seal.vout); + let seal = GenesisSeal::new_random(seal.txid, seal.vout); // Workaround for borrow checker: let field_name = @@ -784,7 +786,7 @@ impl Exec for RgbArgs { .expect("owned state must be a fungible amount") .as_u64() .expect("fungible state must be an integer"); - let seal = BuilderSeal::Revealed(XChain::Bitcoin(seal)); + let seal = BuilderSeal::Revealed(seal); builder = builder .add_fungible_state(field_name, seal, amount) .expect("invalid global state data"); @@ -835,19 +837,12 @@ impl Exec for RgbArgs { .next() .expect("no addresses left") .addr; - Beneficiary::WitnessVout(Pay2Vout { - address: addr.payload, - method: wallet.wallet().seal_close_method(), - }) + Beneficiary::WitnessVout(Pay2Vout::new(addr.payload)) } (_, Some(outpoint)) => { - let seal = XChain::Bitcoin(GraphSeal::new_random( - wallet.wallet().seal_close_method(), - outpoint.txid, - outpoint.vout, - )); + let seal = GraphSeal::new_random(outpoint.txid, outpoint.vout); wallet.stock_mut().store_secret_seal(seal)?; - Beneficiary::BlindedSeal(*seal.to_secret_seal().as_reduced_unsafe()) + Beneficiary::BlindedSeal(seal.to_secret_seal()) } }; @@ -1049,7 +1044,7 @@ impl Exec for RgbArgs { pub struct ConsignmentInspection { version: ContainerVer, transfer: bool, - terminals: SmallOrdMap>, + terminals: SmallOrdMap, supplements: TinyOrdSet, signatures: TinyOrdMap, } @@ -1250,12 +1245,11 @@ impl Exec for RgbArgs { Command::Validate { file } => { let mut resolver = self.resolver()?; let consignment = Transfer::load_file(file)?; - resolver.add_terminals(&consignment); - let status = - match consignment.validate(&resolver, self.general.network.is_testnet()) { - Ok(consignment) => consignment.into_validation_status(), - Err((status, _)) => status, - }; + resolver.add_consignment_txes(&consignment); + let status = match consignment.validate(&resolver, self.chain_net()) { + Ok(consignment) => consignment.into_validation_status(), + Err((status, _)) => status, + }; if status.validity() == Validity::Valid { eprintln!("The provided consignment is valid") } else { @@ -1267,9 +1261,9 @@ impl Exec for RgbArgs { let mut stock = self.rgb_stock()?; let mut resolver = self.resolver()?; let transfer = Transfer::load_file(file)?; - resolver.add_terminals(&transfer); + resolver.add_consignment_txes(&transfer); let valid = transfer - .validate(&resolver, self.general.network.is_testnet()) + .validate(&resolver, self.chain_net()) .map_err(|(status, _)| status)?; stock.accept_transfer(valid, &resolver)?; eprintln!("Transfer accepted into the stash"); diff --git a/examples/rgb20-demo.con b/examples/rgb20-demo.con index bfeef2c..d01c6ea 100644 --- a/examples/rgb20-demo.con +++ b/examples/rgb20-demo.con @@ -29,6 +29,5 @@ contract Test: NonInflatableAsset owned assetOwner state = 1_000_000__000_000_00 seal = - method := tapret1st txid = #01d46e52c4bdb51931a0eae83e958c78bdef9cac2057b36d55370410edafdd42 vout = 0 diff --git a/examples/rgb20-demo.yaml b/examples/rgb20-demo.yaml index 575c6d7..475973a 100644 --- a/examples/rgb20-demo.yaml +++ b/examples/rgb20-demo.yaml @@ -26,5 +26,5 @@ globals: assignments: assetOwner: - seal: tapret1st:b449f7eaa3f98c145b27ad0eeb7b5679ceb567faef7a52479bc995792b65f804:1 + seal: b449f7eaa3f98c145b27ad0eeb7b5679ceb567faef7a52479bc995792b65f804:1 amount: 100000000 # this is 1 million (we have two digits for cents) diff --git a/psbt/src/lib.rs b/psbt/src/lib.rs index ad736c4..510f312 100644 --- a/psbt/src/lib.rs +++ b/psbt/src/lib.rs @@ -26,10 +26,10 @@ mod rgb; use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; +use bp::seals::txout::CloseMethod; pub use bpstd::psbt::*; pub use rgb::*; -use rgbstd::containers::{AnchorSet, Batch, CloseMethodSet, Fascia, PubWitness, XPubWitness}; -use rgbstd::XChain; +use rgbstd::containers::{AnchorSet, Batch, Fascia, PubWitness}; pub use self::rgb::{ ProprietaryKeyRgb, RgbExt, RgbInExt, RgbOutExt, RgbPsbtError, PSBT_GLOBAL_RGB_TRANSITION, @@ -77,7 +77,7 @@ impl RgbPsbt for Psbt { let contract_id = info.transition.contract_id; let mut inputs = info.inputs.release(); for input in self.inputs_mut() { - if inputs.remove(&XChain::Bitcoin(input.prevout().outpoint())) { + if inputs.remove(&input.prevout().outpoint()) { input .set_rgb_consumer(contract_id, info.id) .map_err(|_| EmbedError::PsbtRepeatedInputs)?; @@ -86,7 +86,7 @@ impl RgbPsbt for Psbt { if !inputs.is_empty() { return Err(EmbedError::AbsentInputs); } - self.push_rgb_transition(info.transition, info.method) + self.push_rgb_transition(info.transition) .expect("transitions are unique since they are in BTreeMap indexed by opid"); } Ok(()) @@ -96,30 +96,18 @@ impl RgbPsbt for Psbt { // Convert RGB data to MPCs? Or should we do it at the moment we add them... No, // since we may require more DBC methods with each additional state transition let bundles = self.rgb_bundles_to_mpc()?; - // DBC commitment for the required methods - let methods = bundles - .values() - .flat_map(|b| b.iter()) - .map(|b| CloseMethodSet::from(b.close_method)) - .reduce(|methods, method| methods | method) - .ok_or(RgbPsbtError::NoContracts)?; - let (mut tapret_anchor, mut opret_anchor) = (None, None); - if methods.has_tapret_first() { - tapret_anchor = Some(self.dbc_commit::()?); - } - if methods.has_opret_first() { - opret_anchor = Some(self.dbc_commit::()?); - } - let anchor = match (tapret_anchor, opret_anchor) { - (None, None) => return Err(RgbPsbtError::NoContracts.into()), - (Some(tapret), None) => AnchorSet::Tapret(tapret), - (None, Some(opret)) => AnchorSet::Opret(opret), - (Some(tapret), Some(opret)) => AnchorSet::Double { tapret, opret }, + // DBC commitment for the correct close method + 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::()?), }; // TODO: Use signed transaction here! let witness = PubWitness::with(self.to_unsigned_tx().into()); Ok(Fascia { - witness: XPubWitness::Bitcoin(witness), + witness, anchor, bundles, }) diff --git a/psbt/src/rgb.rs b/psbt/src/rgb.rs index 0a1f14d..c4e389f 100644 --- a/psbt/src/rgb.rs +++ b/psbt/src/rgb.rs @@ -19,7 +19,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::{BTreeMap, BTreeSet, HashMap}; +use std::collections::{BTreeMap, BTreeSet}; use amplify::confinement::{Confined, SmallOrdMap, U24}; use amplify::{confinement, FromSliceError}; @@ -28,7 +28,7 @@ use bp::seals::txout::CloseMethod; use bpstd::psbt; use bpstd::psbt::{KeyAlreadyPresent, KeyMap, MpcPsbtError, PropKey, Psbt}; use commit_verify::mpc; -use rgbstd::containers::{BundleDichotomy, VelocityHint}; +use rgbstd::containers::VelocityHint; use rgbstd::{ ContractId, InputMap, MergeReveal, MergeRevealError, OpId, Operation, Transition, TransitionBundle, Vin, @@ -47,9 +47,9 @@ pub const PSBT_RGB_PREFIX: &str = "RGB"; /// Proprietary key subtype for storing RGB state transition in global map. pub const PSBT_GLOBAL_RGB_TRANSITION: u64 = 0x01; -/// Proprietary key subtype for storing information on which closed methods -/// should be used for each of RGB state transitions. -pub const PSBT_GLOBAL_RGB_CLOSE_METHODS: u64 = 0x02; +/// 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 for storing RGB state transition operation id which /// consumes this input. pub const PSBT_IN_RGB_CONSUMED_BY: u64 = 0x01; @@ -67,12 +67,12 @@ pub trait ProprietaryKeyRgb { data: opid.to_vec().into(), } } - /// Constructs [`PSBT_GLOBAL_RGB_CLOSE_METHODS`] proprietary key. - fn rgb_closing_methods(opid: OpId) -> PropKey { + /// Constructs [`PSBT_GLOBAL_RGB_CLOSE_METHOD`] proprietary key. + fn rgb_close_method() -> PropKey { PropKey { identifier: PSBT_RGB_PREFIX.to_owned(), - subtype: PSBT_GLOBAL_RGB_CLOSE_METHODS, - data: opid.to_vec().into(), + subtype: PSBT_GLOBAL_RGB_CLOSE_METHOD, + data: none!(), } } @@ -111,6 +111,9 @@ pub enum RgbPsbtError { /// PSBT contains no contract information NoContracts, + /// PSBT contains no contract consumers information + NoContractConsumers, + /// contract {0} listed in the PSBT has zero known transition information. NoTransitions(ContractId), @@ -118,12 +121,11 @@ pub enum RgbPsbtError { #[from(FromSliceError)] InvalidContractId, - /// state transition {0} doesn't provide information about seal closing - /// methods used by its inputs. - NoCloseMethod(OpId), + /// PSBT doesn't provide information about close method. + NoCloseMethod, - /// invalid close method data for opid {0} - InvalidCloseMethod(OpId), + /// PSBT provides invalid close method information. + InvalidCloseMethod, /// PSBT doesn't specify an output which can host {0} commitment. NoHostOutput(Method), @@ -160,59 +162,44 @@ pub trait RgbExt { fn rgb_transition(&self, opid: OpId) -> Result, RgbPsbtError>; - fn rgb_close_method(&self, opid: OpId) -> Result, RgbPsbtError>; + fn rgb_close_method(&self) -> Result, RgbPsbtError>; - fn push_rgb_transition( - &mut self, - transition: Transition, - method: CloseMethod, - ) -> Result; + fn set_rgb_close_method(&mut self, close_method: CloseMethod); - fn rgb_bundles(&self) -> Result, RgbPsbtError> { + 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 = HashMap::>::new(); - let mut known_transitions = - HashMap::>::new(); - for (opid, vin) in self.rgb_contract_consumers(contract_id)? { - let (transition, method) = ( - self.rgb_transition(opid)?, - self.rgb_close_method(opid)? - .ok_or(RgbPsbtError::NoCloseMethod(opid))?, - ); - input_map.entry(method).or_default().insert(vin, opid)?; + 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 - .entry(method) - .or_default() - .insert(opid, transition)?; + known_transitions.insert(opid, transition)?; } } - let mut bundles = vec![]; - for (method, input_map) in input_map { - let known_transitions = known_transitions.remove(&method).unwrap_or_default(); - bundles.push(TransitionBundle { - close_method: method, - input_map: InputMap::from( - Confined::try_from(input_map.release()) - .map_err(|_| RgbPsbtError::NoTransitions(contract_id))?, - ), - known_transitions: Confined::try_from(known_transitions.release()) + let bundle = TransitionBundle { + input_map: InputMap::from( + Confined::try_from(input_map.release()) .map_err(|_| RgbPsbtError::NoTransitions(contract_id))?, - }); - } - let mut bundles = bundles.into_iter(); - let first = bundles - .next() - .ok_or(RgbPsbtError::NoTransitions(contract_id))?; - map.insert(contract_id, BundleDichotomy::with(first, bundles.next())); + ), + known_transitions: Confined::try_from(known_transitions.release()) + .map_err(|_| RgbPsbtError::NoTransitions(contract_id))?, + }; + map.insert(contract_id, bundle); } Ok(map) } fn rgb_bundles_to_mpc( &mut self, - ) -> Result, 1, U24>, RgbPsbtError>; + ) -> Result, 1, U24>, RgbPsbtError>; } impl RgbExt for Psbt { @@ -260,8 +247,8 @@ impl RgbExt for Psbt { Ok(Some(transition)) } - fn rgb_close_method(&self, opid: OpId) -> Result, RgbPsbtError> { - let Some(m) = self.proprietary(&PropKey::rgb_closing_methods(opid)) else { + fn rgb_close_method(&self) -> Result, RgbPsbtError> { + let Some(m) = self.proprietary(&PropKey::rgb_close_method()) else { return Ok(None); }; if m.len() == 1 { @@ -269,20 +256,15 @@ impl RgbExt for Psbt { return Ok(Some(method)); } } - Err(RgbPsbtError::InvalidCloseMethod(opid)) + Err(RgbPsbtError::InvalidCloseMethod) } - fn push_rgb_transition( - &mut self, - mut transition: Transition, - method: CloseMethod, - ) -> Result { - let opid = transition.id(); + fn set_rgb_close_method(&mut self, close_method: CloseMethod) { + let _ = self.push_proprietary(PropKey::rgb_close_method(), vec![close_method as u8]); + } - let prev_method = self.rgb_close_method(opid)?; - if matches!(prev_method, Some(prev_method) if prev_method != method) { - return Err(RgbPsbtError::InvalidCloseMethod(opid)); - } + 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 { @@ -300,36 +282,30 @@ impl RgbExt for Psbt { // existed let _ = self.push_proprietary(PropKey::rgb_transition(opid), serialized_transition.release()); - let _ = self.push_proprietary(PropKey::rgb_closing_methods(opid), vec![method as u8]); Ok(prev_transition.is_none()) } fn rgb_bundles_to_mpc( &mut self, - ) -> Result, 1, U24>, RgbPsbtError> { + ) -> Result, 1, U24>, RgbPsbtError> { let bundles = self.rgb_bundles()?; - for (contract_id, bundle) in bundles - .iter() - .flat_map(|(id, b)| b.iter().map(move |b| (id, b))) - { + let close_method = self + .rgb_close_method()? + .ok_or(RgbPsbtError::NoCloseMethod)?; + + let host = self + .outputs_mut() + .find(|output| match close_method { + CloseMethod::OpretFirst => output.is_opret_host(), + CloseMethod::TapretFirst => output.is_tapret_host(), + }) + .ok_or(RgbPsbtError::NoHostOutput(close_method))?; + + for (contract_id, bundle) in &bundles { let protocol_id = mpc::ProtocolId::from(*contract_id); let message = mpc::Message::from(bundle.bundle_id()); - if bundle.close_method == CloseMethod::TapretFirst { - // We need to do it each time due to Rust borrow checker - let tapret_host = self - .outputs_mut() - .find(|output| output.is_tapret_host()) - .ok_or(RgbPsbtError::NoHostOutput(Method::TapretFirst))?; - tapret_host.set_mpc_message(protocol_id, message)?; - } else if bundle.close_method == CloseMethod::OpretFirst { - // We need to do it each time due to Rust borrow checker - let opret_host = self - .outputs_mut() - .find(|output| output.is_opret_host()) - .ok_or(RgbPsbtError::NoHostOutput(Method::OpretFirst))?; - opret_host.set_mpc_message(protocol_id, message)?; - } + host.set_mpc_message(protocol_id, message)?; } let map = Confined::try_from(bundles).map_err(|_| RgbPsbtError::NoContracts)?; diff --git a/src/descriptor.rs b/src/descriptor.rs index 103eee2..8c48b01 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -43,7 +43,7 @@ use indexmap::IndexMap; pub struct TapTweakAlreadyAssigned(pub Terminal); pub trait DescriptorRgb: Descriptor { - fn seal_close_method(&self) -> CloseMethod; + fn close_method(&self) -> CloseMethod; fn add_tapret_tweak( &mut self, terminal: Terminal, @@ -227,7 +227,7 @@ impl Descriptor for TapretKey { } impl DescriptorRgb for TapretKey { - fn seal_close_method(&self) -> CloseMethod { CloseMethod::TapretFirst } + fn close_method(&self) -> CloseMethod { CloseMethod::TapretFirst } fn add_tapret_tweak( &mut self, @@ -368,10 +368,10 @@ impl + DeriveCompr + DeriveXOnly> DescriptorR for RgbDescr where Self: Derive { - fn seal_close_method(&self) -> CloseMethod { + fn close_method(&self) -> CloseMethod { match self { RgbDescr::Wpkh(_) => CloseMethod::OpretFirst, - RgbDescr::TapretKey(d) => d.seal_close_method(), + RgbDescr::TapretKey(d) => d.close_method(), } } diff --git a/src/errors.rs b/src/errors.rs index 72d32b8..1eb856e 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -25,6 +25,7 @@ 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}; @@ -146,6 +147,12 @@ 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), + /// 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. @@ -186,6 +193,12 @@ 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), diff --git a/src/filters.rs b/src/filters.rs index 2cdbd44..8be3f1f 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -19,29 +19,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -use bp::Bp; use bpwallet::{Layer2, Wallet}; use rgbstd::interface::AssignmentsFilter; -use crate::{DescriptorRgb, XChain, XOutpoint, XWitnessId}; +use crate::{DescriptorRgb, Outpoint, Txid}; pub struct WalletOutpointsFilter<'a, K, D: DescriptorRgb, L2: Layer2>(pub &'a Wallet); // We need manual derivation to ensure we can be copied and cloned even if descriptor is not // copyable/clonable. -impl<'a, K, D: DescriptorRgb, L2: Layer2> Copy for WalletOutpointsFilter<'a, K, D, L2> {} -impl<'a, K, D: DescriptorRgb, L2: Layer2> Clone for WalletOutpointsFilter<'a, K, D, L2> { +impl, L2: Layer2> Copy for WalletOutpointsFilter<'_, K, D, L2> {} +impl, L2: Layer2> Clone for WalletOutpointsFilter<'_, K, D, L2> { fn clone(&self) -> Self { *self } } -impl<'a, K, D: DescriptorRgb, L2: Layer2> AssignmentsFilter - for WalletOutpointsFilter<'a, K, D, L2> -{ - fn should_include(&self, output: impl Into, _: Option) -> bool { - match output.into().into_bp() { - Bp::Bitcoin(outpoint) => self.0.has_outpoint(outpoint), - Bp::Liquid(_) => false, - } +impl, L2: Layer2> AssignmentsFilter for WalletOutpointsFilter<'_, K, D, L2> { + fn should_include(&self, outpoint: impl Into, _: Option) -> bool { + self.0.has_outpoint(outpoint.into()) } } @@ -49,19 +43,14 @@ pub struct WalletUnspentFilter<'a, K, D: DescriptorRgb, L2: Layer2>(pub &'a W // We need manual derivation to ensure we can be copied and cloned even if descriptor is not // copyable/clonable. -impl<'a, K, D: DescriptorRgb, L2: Layer2> Copy for WalletUnspentFilter<'a, K, D, L2> {} -impl<'a, K, D: DescriptorRgb, L2: Layer2> Clone for WalletUnspentFilter<'a, K, D, L2> { +impl, L2: Layer2> Copy for WalletUnspentFilter<'_, K, D, L2> {} +impl, L2: Layer2> Clone for WalletUnspentFilter<'_, K, D, L2> { fn clone(&self) -> Self { *self } } -impl<'a, K, D: DescriptorRgb, L2: Layer2> AssignmentsFilter - for WalletUnspentFilter<'a, K, D, L2> -{ - fn should_include(&self, output: impl Into, _: Option) -> bool { - match output.into().into_bp() { - Bp::Bitcoin(outpoint) => self.0.is_unspent(outpoint), - Bp::Liquid(_) => false, - } +impl, L2: Layer2> AssignmentsFilter for WalletUnspentFilter<'_, K, D, L2> { + fn should_include(&self, outpoint: impl Into, _: Option) -> bool { + self.0.is_unspent(outpoint.into()) } } @@ -69,17 +58,15 @@ pub struct WalletWitnessFilter<'a, K, D: DescriptorRgb, L2: Layer2>(pub &'a W // We need manual derivation to ensure we can be copied and cloned even if descriptor is not // copyable/clonable. -impl<'a, K, D: DescriptorRgb, L2: Layer2> Copy for WalletWitnessFilter<'a, K, D, L2> {} -impl<'a, K, D: DescriptorRgb, L2: Layer2> Clone for WalletWitnessFilter<'a, K, D, L2> { +impl, L2: Layer2> Copy for WalletWitnessFilter<'_, K, D, L2> {} +impl, L2: Layer2> Clone for WalletWitnessFilter<'_, K, D, L2> { fn clone(&self) -> Self { *self } } -impl<'a, K, D: DescriptorRgb, L2: Layer2> AssignmentsFilter - for WalletWitnessFilter<'a, K, D, L2> -{ - fn should_include(&self, _: impl Into, witness_id: Option) -> bool { +impl, L2: Layer2> AssignmentsFilter for WalletWitnessFilter<'_, K, D, L2> { + fn should_include(&self, _: impl Into, witness_id: Option) -> bool { self.0 .history() - .any(|row| !row.our_inputs.is_empty() && witness_id == Some(XChain::Bitcoin(row.txid))) + .any(|row| !row.our_inputs.is_empty() && witness_id == Some(row.txid)) } } diff --git a/src/indexers/any.rs b/src/indexers/any.rs index 08b3b7f..b40c952 100644 --- a/src/indexers/any.rs +++ b/src/indexers/any.rs @@ -23,19 +23,17 @@ use std::collections::HashMap; -use bp::Tx; -use bpstd::Network; +use bp::{Tx, Txid}; use rgbstd::containers::Consignment; use rgbstd::validation::{ResolveWitness, WitnessResolverError}; -use rgbstd::XWitnessId; +use rgbstd::ChainNet; -use crate::vm::{WitnessOrd, XWitnessTx}; -use crate::{Txid, XChain}; +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(&self, network: Network, expected_block_hash: String) -> Result<(), String>; + 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; } @@ -45,7 +43,7 @@ pub trait RgbResolver: Send { #[non_exhaustive] pub struct AnyResolver { inner: Box, - terminal_txes: HashMap, + consignment_txes: HashMap, } impl AnyResolver { @@ -56,7 +54,7 @@ impl AnyResolver { electrum::Client::from_config(url, config.unwrap_or_default()) .map_err(|e| e.to_string())?, ), - terminal_txes: Default::default(), + consignment_txes: Default::default(), }) } @@ -67,7 +65,7 @@ impl AnyResolver { esplora::BlockingClient::from_config(url, config.unwrap_or_default()) .map_err(|e| e.to_string())?, ), - terminal_txes: Default::default(), + consignment_txes: Default::default(), }) } @@ -78,76 +76,57 @@ impl AnyResolver { url, config.unwrap_or_default(), )?), - terminal_txes: Default::default(), + consignment_txes: Default::default(), }) } - pub fn check(&self, network: Network) -> Result<(), String> { - let expected_block_hash = match network { - Network::Mainnet => "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", - Network::Testnet3 => "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", - Network::Testnet4 => "00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043", - Network::Signet => "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6", - Network::Regtest => "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206", - } - .to_string(); - self.inner.check(network, expected_block_hash) + + pub fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), String> { + self.inner.check_chain_net(chain_net) } - pub fn add_terminals(&mut self, consignment: &Consignment) { - self.terminal_txes.extend( + /// 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.maybe_map_ref(|w| w.tx().cloned())) - .filter_map(|tx| match tx { - XChain::Bitcoin(tx) => Some(tx), - XChain::Liquid(_) | XChain::Other(_) => None, - }) + .filter_map(|bw| bw.pub_witness.tx().cloned()) .map(|tx| (tx.txid(), tx)), ); } } impl ResolveWitness for AnyResolver { - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result { - let XWitnessId::Bitcoin(txid) = witness_id else { - return Err(WitnessResolverError::Other( - witness_id, - format!("{} is not supported as layer 1 network", witness_id.layer1()), - )); - }; - - if let Some(tx) = self.terminal_txes.get(&txid) { - return Ok(XWitnessTx::Bitcoin(tx.clone())); + 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(txid) + .resolve_pub_witness(witness_id) .map_err(|e| WitnessResolverError::Other(witness_id, e)) .and_then(|r| r.ok_or(WitnessResolverError::Unknown(witness_id))) - .map(XChain::Bitcoin) } fn resolve_pub_witness_ord( &self, - witness_id: XWitnessId, + witness_id: Txid, ) -> Result { - let XWitnessId::Bitcoin(txid) = witness_id else { - return Err(WitnessResolverError::Other( - witness_id, - format!("{} is not supported as layer 1 network", witness_id.layer1()), - )); - }; - - if self.terminal_txes.contains_key(&txid) { + if self.consignment_txes.contains_key(&witness_id) { return Ok(WitnessOrd::Tentative); } self.inner - .resolve_pub_witness_ord(txid) + .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 index 98aad72..a8faa0f 100644 --- a/src/indexers/electrum_blocking.rs +++ b/src/indexers/electrum_blocking.rs @@ -25,10 +25,11 @@ use std::iter; use std::num::NonZeroU32; use bp::ConsensusDecode; -use bpstd::{Network, Tx, Txid}; +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; @@ -40,20 +41,31 @@ macro_rules! check { } impl RgbResolver for Client { - fn check(&self, network: Network, expected_block_hash: String) -> Result<(), String> { + 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().to_string(); - if expected_block_hash != block_hash { + 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 network { - Network::Mainnet => "33e794d097969002ee05d336686fc03c9e15a597c1b9827669460fac98799036", - Network::Testnet3 => "5e6560fd518aadbed67ee4a55bdc09f19e619544f5511e9343ebba66d2f62653", - Network::Testnet4 => "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e", - Network::Signet => "8153034f45e695453250a8fb7225a5e545144071d8ed7b0d3211efa1f3c92ad8", - Network::Regtest => "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + 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()), diff --git a/src/indexers/esplora_blocking.rs b/src/indexers/esplora_blocking.rs index e72e2fa..1bcaa78 100644 --- a/src/indexers/esplora_blocking.rs +++ b/src/indexers/esplora_blocking.rs @@ -22,19 +22,20 @@ use std::num::NonZeroU32; use bp::Tx; -use bpstd::{Network, Txid}; +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(&self, _network: Network, expected_block_hash: String) -> Result<(), String> { + 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)?.to_string(); - if expected_block_hash != block_hash { + 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(()) diff --git a/src/indexers/mempool_blocking.rs b/src/indexers/mempool_blocking.rs index 6dc0017..0a1ca10 100644 --- a/src/indexers/mempool_blocking.rs +++ b/src/indexers/mempool_blocking.rs @@ -20,9 +20,10 @@ // limitations under the License. use bp::Tx; -use bpstd::{Network, Txid}; +use bpstd::Txid; use esplora::{BlockingClient, Config, Error}; use rgbstd::vm::WitnessOrd; +use rgbstd::ChainNet; use super::RgbResolver; @@ -56,8 +57,8 @@ impl MemPoolClient { } impl RgbResolver for MemPoolClient { - fn check(&self, network: Network, expected_block_hash: String) -> Result<(), String> { - self.inner.check(network, expected_block_hash) + 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 { diff --git a/src/lib.rs b/src/lib.rs index d37fcf1..0f10d7b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,22 +37,25 @@ pub use errors::{CompletionError, CompositionError, PayError, WalletError}; pub use pay::{TransferParams, WalletProvider}; pub use rgbstd::*; pub mod resolvers { + use bp::Tx; + 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, XWitnessTx}; - use super::XWitnessId; + use super::vm::WitnessOrd; + use super::Txid; pub struct ContractIssueResolver; impl ResolveWitness for ContractIssueResolver { - fn resolve_pub_witness(&self, _: XWitnessId) -> Result { + fn resolve_pub_witness(&self, _: Txid) -> Result { + panic!("contract issue resolver must not be used for an already-existing contracts") + } + fn resolve_pub_witness_ord(&self, _: Txid) -> Result { panic!("contract issue resolver must not be used for an already-existing contracts") } - fn resolve_pub_witness_ord( - &self, - _: XWitnessId, - ) -> Result { + fn check_chain_net(&self, _: ChainNet) -> Result<(), WitnessResolverError> { panic!("contract issue resolver must not be used for an already-existing contracts") } } diff --git a/src/pay.rs b/src/pay.rs index 8123562..a3a14d4 100644 --- a/src/pay.rs +++ b/src/pay.rs @@ -23,27 +23,27 @@ use std::collections::{BTreeMap, BTreeSet}; use std::marker::PhantomData; use bp::dbc::tapret::TapretProof; -use bp::seals::txout::ExplicitSeal; -use bp::{Outpoint, Sats, ScriptPubkey, Vout}; +use bp::seals::txout::{CloseMethod, ExplicitSeal}; +use bp::{Outpoint, Sats, ScriptPubkey, Tx, Vout}; use bpstd::{psbt, Address}; use bpwallet::{Layer2, Layer2Tx, NoLayer2, TxRow, Wallet, WalletDescr}; use psrgbt::{ - Beneficiary as BpBeneficiary, Psbt, PsbtConstructor, PsbtMeta, RgbPsbt, TapretKeyError, + Beneficiary as BpBeneficiary, Psbt, PsbtConstructor, PsbtMeta, RgbExt, RgbPsbt, TapretKeyError, TxParams, }; -use rgbstd::containers::Transfer; +use rgbstd::containers::{AnchorSet, Transfer}; use rgbstd::interface::AssignmentsFilter; use rgbstd::invoice::{Amount, Beneficiary, InvoiceState, RgbInvoice}; use rgbstd::persistence::{IndexProvider, StashProvider, StateProvider, Stock}; use rgbstd::validation::ResolveWitness; -use rgbstd::{ContractId, DataState, XChain, XOutpoint}; +use rgbstd::{ChainNet, ContractId, DataState}; use crate::invoice::NonFungible; use crate::validation::WitnessResolverError; -use crate::vm::{WitnessOrd, XWitnessTx}; +use crate::vm::WitnessOrd; use crate::{ CompletionError, CompositionError, DescriptorRgb, PayError, RgbKeychain, Txid, - WalletOutpointsFilter, WalletUnspentFilter, WalletWitnessFilter, XWitnessId, + WalletOutpointsFilter, WalletUnspentFilter, WalletWitnessFilter, }; #[derive(Clone, PartialEq, Debug)] @@ -80,18 +80,16 @@ struct ContractOutpointsFilter< } impl< - 'stock, - 'wallet, W: WalletProvider + ?Sized, K, S: StashProvider, H: StateProvider, P: IndexProvider, L2: Layer2, - > AssignmentsFilter for ContractOutpointsFilter<'stock, 'wallet, W, K, S, H, P, L2> + > AssignmentsFilter for ContractOutpointsFilter<'_, '_, W, K, S, H, P, L2> where W::Descr: DescriptorRgb { - fn should_include(&self, output: impl Into, id: Option) -> bool { + fn should_include(&self, output: impl Into, id: Option) -> bool { let output = output.into(); if !self.wallet.filter_unspent().should_include(output, id) { return false; @@ -141,7 +139,8 @@ where Self::Descr: DescriptorRgb mut params: TransferParams, ) -> Result<(Psbt, PsbtMeta), CompositionError> { let contract_id = invoice.contract.ok_or(CompositionError::NoContract)?; - let method = self.descriptor().seal_close_method(); + + let close_method = self.descriptor().close_method(); let iface_name = invoice.iface.clone().ok_or(CompositionError::NoIface)?; let iface = stock.iface(iface_name.clone()).map_err(|e| e.to_string())?; @@ -220,7 +219,7 @@ where Self::Descr: DescriptorRgb Beneficiary::BlindedSeal(_) => vec![], Beneficiary::WitnessVout(pay2vout) => { vec![BpBeneficiary::new( - Address::new(pay2vout.address, invoice.address_network()), + Address::new(*pay2vout, invoice.address_network()), params.min_amount, )] } @@ -228,18 +227,14 @@ where Self::Descr: DescriptorRgb if prev_outputs.is_empty() { return Err(CompositionError::InsufficientState); } - let prev_outpoints = prev_outputs - .iter() - // TODO: Support liquid - .map(|o| o.as_reduced_unsafe()) - .map(|o| Outpoint::new(o.txid, o.vout)); - params.tx.change_keychain = RgbKeychain::for_method(method).into(); + 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 (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.address.script_pubkey()) + Some(pay2vout.script_pubkey()) } else { None }; @@ -252,11 +247,18 @@ where Self::Descr: DescriptorRgb .change_vout .and_then(|vout| psbt.output(vout.to_usize())) .map(|output| output.script.clone()); - psbt.sort_outputs_by(|output| !output.is_tapret_host()) - .expect("PSBT must be modifiable at this stage"); - if let Some(change_script) = change_script { + 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"); + }; + if let Some(ref change_script) = change_script { for output in psbt.outputs() { - if output.script == change_script { + if output.script == *change_script { meta.change_vout = Some(output.vout()); break; } @@ -265,7 +267,7 @@ where Self::Descr: DescriptorRgb let beneficiary_vout = match invoice.beneficiary.into_inner() { Beneficiary::WitnessVout(pay2vout) => { - let s = pay2vout.address.script_pubkey(); + let s = (*pay2vout).script_pubkey(); let vout = psbt .outputs() .find(|output| output.script == s) @@ -277,15 +279,10 @@ where Self::Descr: DescriptorRgb Beneficiary::BlindedSeal(_) => None, }; let batch = stock - .compose(invoice, prev_outputs, method, beneficiary_vout, |_, _, _| meta.change_vout) + .compose(invoice, prev_outputs, beneficiary_vout, |_, _, _| meta.change_vout) .map_err(|e| e.to_string())?; - let methods = batch.close_method_set(); - if methods.has_opret_first() { - let output = psbt.construct_output_expect(ScriptPubkey::op_return(&[]), Sats::ZERO); - output.set_opret_host().expect("just created"); - } - + psbt.set_rgb_close_method(close_method); psbt.complete_construction(); psbt.rgb_embed(batch)?; Ok((psbt, meta)) @@ -301,7 +298,7 @@ where Self::Descr: DescriptorRgb let contract_id = invoice.contract.ok_or(CompletionError::NoContract)?; let fascia = psbt.rgb_commit()?; - if fascia.anchor.has_tapret() { + if matches!(fascia.anchor, AnchorSet::Tapret(_)) { let output = psbt .dbc_output::() .ok_or(TapretKeyError::NotTaprootOutput)?; @@ -314,50 +311,45 @@ where Self::Descr: DescriptorRgb })?; } - let witness_txid = psbt.txid(); + let witness_id = psbt.txid(); let (beneficiary1, beneficiary2) = match invoice.beneficiary.into_inner() { Beneficiary::WitnessVout(pay2vout) => { - let s = pay2vout.address.script_pubkey(); + 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 = XChain::Bitcoin(ExplicitSeal::new( - pay2vout.method, - Outpoint::new(witness_txid, vout), - )); + let seal = ExplicitSeal::new(Outpoint::new(witness_id, vout)); (None, vec![seal]) } - Beneficiary::BlindedSeal(seal) => (Some(XChain::Bitcoin(seal)), vec![]), + Beneficiary::BlindedSeal(seal) => (Some(seal), vec![]), }; struct FasciaResolver { - witness_id: XWitnessId, + witness_id: Txid, } impl ResolveWitness for FasciaResolver { - fn resolve_pub_witness( - &self, - _: XWitnessId, - ) -> Result { + fn resolve_pub_witness(&self, _: Txid) -> Result { unreachable!() } fn resolve_pub_witness_ord( &self, - witness_id: XWitnessId, + witness_id: Txid, ) -> Result { assert_eq!(witness_id, self.witness_id); Ok(WitnessOrd::Tentative) } + fn check_chain_net(&self, _: ChainNet) -> Result<(), WitnessResolverError> { + unreachable!() + } } stock - .consume_fascia(fascia, FasciaResolver { - witness_id: XChain::Bitcoin(witness_txid), - }) + .consume_fascia(fascia, FasciaResolver { witness_id }) .map_err(|e| e.to_string())?; let transfer = stock - .transfer(contract_id, beneficiary2, beneficiary1) + .transfer(contract_id, beneficiary2, beneficiary1, Some(witness_id)) .map_err(|e| e.to_string())?; Ok(transfer)