diff --git a/Cargo.lock b/Cargo.lock index e440641d..46cee563 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,9 +146,9 @@ checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base85" @@ -218,13 +218,12 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.11.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190ac89a2a3c79d5bfb677f48e5393691832c540973341831572edaffdce0881" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#d90f5774e3b8d41cb97bb2f1113d8c00351d2291" dependencies = [ "amplify", "chrono", "commit_verify", - "secp256k1 0.28.0", + "secp256k1", "serde", "strict_encoding", "strict_types", @@ -233,31 +232,31 @@ dependencies = [ [[package]] name = "bp-core" version = "0.11.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69269d27e32d784e37f7ca7cdf964fe5e30c5bff1ca2e229a118c84c8efdd179" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#d90f5774e3b8d41cb97bb2f1113d8c00351d2291" dependencies = [ "amplify", "bp-consensus", "bp-dbc", "bp-seals", "commit_verify", + "getrandom", "serde", "single_use_seals", "strict_encoding", "strict_types", + "wasm-bindgen", ] [[package]] name = "bp-dbc" version = "0.11.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cef9a98c7ae4f1bb333ad8e55c9d8a91f071c347d35b62e19959faa07572b11" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#d90f5774e3b8d41cb97bb2f1113d8c00351d2291" dependencies = [ "amplify", "base85", "bp-consensus", "commit_verify", - "secp256k1 0.28.0", + "secp256k1", "serde", "strict_encoding", ] @@ -265,7 +264,7 @@ dependencies = [ [[package]] name = "bp-invoice" version = "0.11.0-beta.3.1" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#b37cdba13786091e6e153add0c2beda9c6650ea1" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#d2b7ded652bc51e5701b7a1a737fc046aa0583df" dependencies = [ "amplify", "bech32", @@ -276,8 +275,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.11.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d211bb77e320abf4bba6c272fc85d73e5203140ca39e299271f4714d8b6029fe" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#d90f5774e3b8d41cb97bb2f1113d8c00351d2291" dependencies = [ "amplify", "baid58", @@ -319,9 +317,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" dependencies = [ "android-tzdata", "iana-time-zone", @@ -384,9 +382,9 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -444,9 +442,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "js-sys", @@ -484,9 +482,9 @@ checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -507,9 +505,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b" dependencies = [ "equivalent", "hashbrown", @@ -523,9 +521,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] @@ -538,9 +536,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.151" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "log" @@ -605,18 +603,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.71" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -654,12 +652,13 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.4" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.11#2b59903039770df4766c9681bc74691382308ef5" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.11#3d88aa308674cf464e879a6439fe4f8382596845" dependencies = [ "aluvm", "amplify", "baid58", "bp-core", + "chrono", "commit_verify", "getrandom", "mime", @@ -741,92 +740,72 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "secp256k1" -version = "0.27.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +checksum = "3f622567e3b4b38154fb8190bcf6b160d7a4301d70595a49195b48c116007a27" dependencies = [ "rand", - "secp256k1-sys 0.8.1", - "serde", -] - -[[package]] -name = "secp256k1" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" -dependencies = [ - "rand", - "secp256k1-sys 0.9.1", + "secp256k1-sys", "serde", ] [[package]] name = "secp256k1-sys" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" -dependencies = [ - "cc", -] - -[[package]] -name = "secp256k1-sys" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd97a086ec737e30053fd5c46f097465d25bb81dd3608825f65298c4c98be83" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" dependencies = [ "cc", ] [[package]] name = "secp256k1-zkp" -version = "0.9.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "026efcdacb95ee6aae5cc19144dc1549973eac36a4972700c28493de1ee5d69f" +checksum = "c4e48ef9c98bfbcb98bd15693ffa19676cb3e29426b75eda8b73c05cdd7959f8" dependencies = [ "bitcoin-private", "rand", - "secp256k1 0.27.0", + "secp256k1", "secp256k1-zkp-sys", "serde", ] [[package]] name = "secp256k1-zkp-sys" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03ab1ca75a18e1899e8d9b8d28b5998ae1ddcb42fec5956769718543293c723" +checksum = "b4ead52f43074bae2ddbd1e0e66e6b170135e76117f5ea9916f33d7bd0b36e29" dependencies = [ "cc", - "secp256k1-sys 0.8.1", + "secp256k1-sys", ] [[package]] name = "serde" -version = "1.0.193" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ "itoa", "ryu", @@ -854,9 +833,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.29" +version = "0.9.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15e0ef66bf939a7c890a0bf6d5a733c70202225f9888a89ed5c62298b019129" +checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" dependencies = [ "indexmap", "itoa", @@ -952,9 +931,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.43" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -963,22 +942,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.52" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.52" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -1047,9 +1026,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1057,24 +1036,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" dependencies = [ "cfg-if", "js-sys", @@ -1084,9 +1063,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1094,28 +1073,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "wasm-bindgen-test" -version = "0.3.39" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cf9242c0d27999b831eae4767b2a146feb0b27d332d553e605864acd2afd403" +checksum = "139bd73305d50e1c1c4333210c0db43d989395b64a237bd35c10ef3832a7f70c" dependencies = [ "console_error_panic_hook", "js-sys", @@ -1127,20 +1106,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.39" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794645f5408c9a039fd09f4d113cdfb2e7eba5ff1956b07bcf701cf4b394fe89" +checksum = "70072aebfe5da66d2716002c729a14e4aec4da0e23cc2ea66323dac541c93928" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" dependencies = [ "js-sys", "wasm-bindgen", @@ -1148,18 +1127,18 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1172,51 +1151,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.31" +version = "0.5.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" +checksum = "1931d78a9c73861da0134f453bb1f790ce49b2e30eba8410b4b79bac72b46a2d" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index f373768a..319d5d6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,5 +93,9 @@ wasm-bindgen-test = "0.3" features = [ "all" ] [patch.crates-io] +bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } +bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } +bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } +bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } bp-invoice = { git = "https://github.com/BP-WG/bp-std", branch = "v0.11" } rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "v0.11" } diff --git a/invoice/src/amount.rs b/invoice/src/amount.rs index b34a6899..d13cf177 100644 --- a/invoice/src/amount.rs +++ b/invoice/src/amount.rs @@ -137,6 +137,26 @@ impl Amount { pub fn saturating_sub_assign(&mut self, other: impl Into) { *self = self.0.saturating_sub(other.into().0).into(); } + + #[must_use] + pub fn checked_add(&self, other: impl Into) -> Option { + self.0.checked_add(other.into().0).map(Self) + } + #[must_use] + pub fn checked_sub(&self, other: impl Into) -> Option { + self.0.checked_sub(other.into().0).map(Self) + } + + #[must_use] + pub fn checked_add_assign(&mut self, other: impl Into) -> Option<()> { + *self = self.0.checked_add(other.into().0).map(Self)?; + Some(()) + } + #[must_use] + pub fn checked_sub_assign(&mut self, other: impl Into) -> Option<()> { + *self = self.0.checked_sub(other.into().0).map(Self)?; + Some(()) + } } impl Sum for Amount { diff --git a/invoice/src/parse.rs b/invoice/src/parse.rs index e23a3d3f..0bf1b7b4 100644 --- a/invoice/src/parse.rs +++ b/invoice/src/parse.rs @@ -367,7 +367,7 @@ impl FromStr for RgbInvoice { let beneficiary = XChainNet::::from_str(beneficiary_str)?; let mut query_params = map_query_params(&uri)?; - let transports = if let Some(endpoints) = query_params.remove(ENDPOINTS) { + let transports = if let Some(endpoints) = query_params.shift_remove(ENDPOINTS) { let tokens = endpoints.split(TRANSPORT_SEP); let mut transport_vec: Vec = vec![]; for token in tokens { @@ -382,7 +382,7 @@ impl FromStr for RgbInvoice { }; let mut expiry = None; - if let Some(exp) = query_params.remove(EXPIRY) { + if let Some(exp) = query_params.shift_remove(EXPIRY) { let timestamp = exp .parse::() .map_err(|e| InvoiceParseError::InvalidExpiration(e.to_string()))?; diff --git a/src/containers/consignment.rs b/src/containers/consignment.rs index 46ac4639..7d8bdd42 100644 --- a/src/containers/consignment.rs +++ b/src/containers/consignment.rs @@ -31,7 +31,7 @@ use rgb::{ }; use strict_encoding::{StrictDeserialize, StrictDumb, StrictSerialize}; -use super::{ContainerVer, ContentId, ContentSigs, Terminal}; +use super::{Bindle, BindleContent, ContainerVer, ContentId, ContentSigs, Terminal}; use crate::accessors::BundleExt; use crate::interface::{ContractSuppl, IfaceId, IfacePair}; use crate::resolvers::ResolveHeight; @@ -252,4 +252,10 @@ impl Consignment { signatures: self.signatures, } } + + #[inline] + pub fn unsigned_bindle(self) -> Bindle + where Self: BindleContent { + Bindle::new(self) + } } diff --git a/src/containers/seal.rs b/src/containers/seal.rs index ad0c0ea5..a7d13ab9 100644 --- a/src/containers/seal.rs +++ b/src/containers/seal.rs @@ -25,7 +25,7 @@ use bp::seals::txout::{BlindSeal, CloseMethod, SealTxid}; use bp::secp256k1::rand::{thread_rng, RngCore}; use bp::Vout; use commit_verify::Conceal; -use rgb::{GraphSeal, SecretSeal, TxoSeal, XChain}; +use rgb::{GraphSeal, Layer1, SecretSeal, TxoSeal, XChain}; use crate::LIB_NAME_RGB_STD; @@ -175,3 +175,12 @@ pub enum BuilderSeal { impl From>> for BuilderSeal> { fn from(seal: XChain>) -> Self { BuilderSeal::Revealed(seal) } } + +impl BuilderSeal { + pub fn layer1(&self) -> Layer1 { + match self { + BuilderSeal::Revealed(x) => x.layer1(), + BuilderSeal::Concealed(x) => x.layer1(), + } + } +} diff --git a/src/interface/builder.rs b/src/interface/builder.rs index 348cbb82..be40e45f 100644 --- a/src/interface/builder.rs +++ b/src/interface/builder.rs @@ -19,35 +19,38 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![allow(clippy::result_large_err)] + use std::collections::{BTreeMap, HashSet}; use amplify::confinement::{Confined, TinyOrdMap, TinyOrdSet, U16}; use amplify::{confinement, Wrapper}; use invoice::{Allocation, Amount}; use rgb::{ - AltLayer1, AltLayer1Set, AssetTag, Assign, AssignmentType, Assignments, BlindingFactor, - ContractId, DataState, ExposedSeal, FungibleType, Genesis, GenesisSeal, GlobalState, GraphSeal, - Input, Opout, RevealedAttach, RevealedData, RevealedValue, StateSchema, SubSchema, Transition, - TransitionType, TypedAssigns, + validation, AltLayer1, AltLayer1Set, AssetTag, Assign, AssignmentType, Assignments, + BlindingFactor, ContractId, DataState, ExposedSeal, FungibleType, Genesis, GenesisSeal, + GlobalState, GraphSeal, Input, Layer1, Opout, RevealedAttach, RevealedData, RevealedValue, + StateSchema, SubSchema, Transition, TransitionType, TypedAssigns, XChain, XOutpoint, }; use strict_encoding::{FieldName, SerializeError, StrictSerialize, TypeName}; use strict_types::decode; use crate::containers::{BuilderSeal, Contract}; use crate::interface::contract::AttachedState; -use crate::interface::{Iface, IfaceImpl, IfacePair, TransitionIface}; -use crate::persistence::PresistedState; +use crate::interface::resolver::DumbResolver; +use crate::interface::{ + Iface, IfaceClass, IfaceImpl, IfacePair, IssuerTriplet, SchemaIssuer, TransitionIface, + WrongImplementation, +}; +use crate::persistence::PersistedState; +use crate::Outpoint; #[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] #[display(doc_comments)] pub enum BuilderError { - /// interface implementation references different interface that the one - /// provided to the builder. - InterfaceMismatch, - - /// interface implementation references different schema that the one - /// provided to the builder. - SchemaMismatch, + #[from] + #[display(inner)] + WrongImplementation(WrongImplementation), /// contract already has too many layers1. TooManyLayers1, @@ -86,6 +89,9 @@ pub enum BuilderError { /// interface doesn't have a default assignment type. NoDefaultAssignment, + /// {0} is not supported by the contract genesis. + InvalidLayer1(Layer1), + #[from] #[display(inner)] StrictEncode(SerializeError), @@ -97,6 +103,35 @@ pub enum BuilderError { #[from] #[display(inner)] Confinement(confinement::Error), + + #[from] + #[display(inner)] + ContractInconsistency(validation::Status), +} + +mod private { + pub trait Sealed {} +} + +pub trait TxOutpoint: Copy + Eq + private::Sealed { + fn is_liquid(&self) -> bool; + fn is_bitcoin(&self) -> bool; + fn map_to_xchain(self, f: impl FnOnce(Outpoint) -> U) -> XChain; +} + +impl private::Sealed for Outpoint {} +impl private::Sealed for XOutpoint {} +impl TxOutpoint for Outpoint { + fn is_liquid(&self) -> bool { false } + fn is_bitcoin(&self) -> bool { true } + fn map_to_xchain(self, f: impl FnOnce(Outpoint) -> U) -> XChain { + XChain::Bitcoin(f(self)) + } +} +impl TxOutpoint for XOutpoint { + fn is_liquid(&self) -> bool { XChain::is_liquid(self) } + fn is_bitcoin(&self) -> bool { XChain::is_bitcoin(self) } + fn map_to_xchain(self, f: impl FnOnce(Outpoint) -> U) -> XChain { self.map(f) } } #[derive(Clone, Debug)] @@ -112,7 +147,7 @@ impl ContractBuilder { schema: SubSchema, iimpl: IfaceImpl, testnet: bool, - ) -> Result { + ) -> Result { Ok(Self { builder: OperationBuilder::with(iface, schema, iimpl)?, testnet, @@ -124,7 +159,7 @@ impl ContractBuilder { iface: Iface, schema: SubSchema, iimpl: IfaceImpl, - ) -> Result { + ) -> Result { Ok(Self { builder: OperationBuilder::with(iface, schema, iimpl)?, testnet: false, @@ -136,7 +171,7 @@ impl ContractBuilder { iface: Iface, schema: SubSchema, iimpl: IfaceImpl, - ) -> Result { + ) -> Result { Ok(Self { builder: OperationBuilder::with(iface, schema, iimpl)?, testnet: true, @@ -144,6 +179,19 @@ impl ContractBuilder { }) } + pub fn has_layer1(&self, layer1: Layer1) -> bool { + match layer1 { + Layer1::Bitcoin => true, + Layer1::Liquid => self.alt_layers1.contains(&AltLayer1::Liquid), + } + } + pub fn check_layer1(&self, layer1: Layer1) -> Result<(), BuilderError> { + if !self.has_layer1(layer1) { + return Err(BuilderError::InvalidLayer1(layer1)); + } + Ok(()) + } + pub fn add_layer1(mut self, layer1: AltLayer1) -> Result { self.alt_layers1 .push(layer1) @@ -151,6 +199,11 @@ impl ContractBuilder { Ok(self) } + #[inline] + pub fn asset_tag(&self, name: impl Into) -> Result { + self.builder.asset_tag(name) + } + #[inline] pub fn add_asset_tag( mut self, @@ -171,13 +224,15 @@ impl ContractBuilder { Ok(self) } - pub fn add_owned_state_raw( + pub fn add_owned_state_det( mut self, - type_id: AssignmentType, + name: impl Into, seal: impl Into>, - state: PresistedState, + state: PersistedState, ) -> Result { - self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?; + let seal = seal.into(); + self.check_layer1(seal.layer1())?; + self.builder = self.builder.add_owned_state_det(name, seal, state)?; Ok(self) } @@ -186,6 +241,8 @@ impl ContractBuilder { name: impl Into, seal: impl Into>, ) -> Result { + let seal = seal.into(); + self.check_layer1(seal.layer1())?; self.builder = self.builder.add_rights(name, seal, None)?; Ok(self) } @@ -197,6 +254,8 @@ impl ContractBuilder { value: u64, ) -> Result { let name = name.into(); + let seal = seal.into(); + self.check_layer1(seal.layer1())?; let type_id = self .builder .assignments_type(&name, None) @@ -229,6 +288,8 @@ impl ContractBuilder { seal: impl Into>, value: impl StrictSerialize, ) -> Result { + let seal = seal.into(); + self.check_layer1(seal.layer1())?; self.builder = self.builder.add_data(name, seal, value, None)?; Ok(self) } @@ -239,6 +300,8 @@ impl ContractBuilder { seal: impl Into>, attachment: AttachedState, ) -> Result { + let seal = seal.into(); + self.check_layer1(seal.layer1())?; self.builder = self.builder.add_attachment(name, seal, attachment, None)?; Ok(self) } @@ -257,12 +320,19 @@ impl ContractBuilder { valencies: none!(), }; - // TODO: Validate against schema - let mut contract = Contract::new(schema, genesis, asset_tags); contract.ifaces = tiny_bmap! { iface_pair.iface_id() => iface_pair }; - Ok(contract) + let verified_contract = + contract + .validate(&mut DumbResolver, self.testnet) + .map_err(|consignment| { + consignment + .into_validation_status() + .expect("status always present upon validation") + })?; + + Ok(verified_contract) } } @@ -270,7 +340,7 @@ impl ContractBuilder { pub struct TransitionBuilder { builder: OperationBuilder, transition_type: TransitionType, - inputs: TinyOrdMap, + inputs: TinyOrdMap, } impl TransitionBuilder { @@ -278,7 +348,7 @@ impl TransitionBuilder { iface: Iface, schema: SubSchema, iimpl: IfaceImpl, - ) -> Result { + ) -> Result { Self::with(iface, schema, iimpl, TransitionType::BLANK) } @@ -292,7 +362,7 @@ impl TransitionBuilder { .as_ref() .and_then(|name| iimpl.transition_type(name)) .ok_or(BuilderError::NoOperationSubtype)?; - Self::with(iface, schema, iimpl, transition_type) + Ok(Self::with(iface, schema, iimpl, transition_type)?) } pub fn named_transition( @@ -305,7 +375,7 @@ impl TransitionBuilder { let transition_type = iimpl .transition_type(&transition_name) .ok_or(BuilderError::TransitionNotFound(transition_name))?; - Self::with(iface, schema, iimpl, transition_type) + Ok(Self::with(iface, schema, iimpl, transition_type)?) } fn with( @@ -313,7 +383,7 @@ impl TransitionBuilder { schema: SubSchema, iimpl: IfaceImpl, transition_type: TransitionType, - ) -> Result { + ) -> Result { Ok(Self { builder: OperationBuilder::with(iface, schema, iimpl)?, transition_type, @@ -323,6 +393,11 @@ impl TransitionBuilder { pub fn transition_type(&self) -> TransitionType { self.transition_type } + #[inline] + pub fn asset_tag(&self, name: impl Into) -> Result { + self.builder.asset_tag(name) + } + #[inline] pub fn add_asset_tag( mut self, @@ -355,7 +430,7 @@ impl TransitionBuilder { Ok(self) } - pub fn add_input(mut self, opout: Opout, state: PresistedState) -> Result { + pub fn add_input(mut self, opout: Opout, state: PersistedState) -> Result { self.inputs.insert(Input::with(opout), state)?; Ok(self) } @@ -374,13 +449,23 @@ impl TransitionBuilder { .assignments_type(name, Some(self.transition_type)) } + pub fn add_owned_state_det( + mut self, + name: impl Into, + seal: impl Into>, + state: PersistedState, + ) -> Result { + self.builder = self.builder.add_owned_state_det(name, seal, state)?; + Ok(self) + } + pub fn add_owned_state_raw( mut self, type_id: AssignmentType, seal: impl Into>, - state: PresistedState, + state: PersistedState, ) -> Result { - if matches!(state, PresistedState::Amount(_, _, tag) if self.builder.asset_tag(type_id)? != tag) + if matches!(state, PersistedState::Amount(_, _, tag) if self.builder.asset_tag_raw(type_id)? != tag) { return Err(BuilderError::AssetTagInvalid(type_id)); } @@ -415,7 +500,7 @@ impl TransitionBuilder { value: impl Into, blinding: BlindingFactor, ) -> Result { - let tag = self.builder.asset_tag(type_id)?; + let tag = self.builder.asset_tag_raw(type_id)?; let state = RevealedValue::with_blinding(value.into(), blinding, tag); self.builder = self.builder.add_fungible_state_raw(type_id, seal, state)?; Ok(self) @@ -432,7 +517,7 @@ impl TransitionBuilder { .builder .assignments_type(&name, None) .ok_or(BuilderError::AssignmentNotFound(name.clone()))?; - let tag = self.builder.asset_tag(type_id)?; + let tag = self.builder.asset_tag_raw(type_id)?; self.builder = self.builder @@ -525,20 +610,11 @@ pub struct OperationBuilder { // TODO: add valencies } -impl OperationBuilder { - fn with(iface: Iface, schema: SubSchema, iimpl: IfaceImpl) -> Result { - if iimpl.iface_id != iface.iface_id() { - return Err(BuilderError::InterfaceMismatch); - } - if iimpl.schema_id != schema.schema_id() { - return Err(BuilderError::SchemaMismatch); - } +impl From for OperationBuilder { + fn from(triplet: IssuerTriplet) -> Self { + let (iface, schema, iimpl) = triplet.into_split(); - // TODO: check schema internal consistency - // TODO: check interface internal consistency - // TODO: check implementation internal consistency - - Ok(OperationBuilder { + OperationBuilder { schema, iface, iimpl, @@ -549,7 +625,22 @@ impl OperationBuilder { fungible: none!(), attachments: none!(), data: none!(), - }) + } + } +} + +impl From> for OperationBuilder { + fn from(issuer: SchemaIssuer) -> Self { Self::from(issuer.into_triplet()) } +} + +impl OperationBuilder { + fn with( + iface: Iface, + schema: SubSchema, + iimpl: IfaceImpl, + ) -> Result { + let triplet = IssuerTriplet::new(iface, schema, iimpl)?; + Ok(Self::from(triplet)) } fn transition_iface(&self, ty: TransitionType) -> &TransitionIface { @@ -581,8 +672,16 @@ impl OperationBuilder { .expect("schema should match interface: must be checked by the constructor") } + pub fn asset_tag(&self, name: impl Into) -> Result { + let name = name.into(); + let type_id = self + .assignments_type(&name, None) + .ok_or(BuilderError::AssignmentNotFound(name.clone()))?; + self.asset_tag_raw(type_id) + } + #[inline] - pub fn asset_tag(&self, type_id: AssignmentType) -> Result { + fn asset_tag_raw(&self, type_id: AssignmentType) -> Result { self.asset_tags .get(&type_id) .ok_or(BuilderError::AssetTagMissed(type_id)) @@ -652,23 +751,42 @@ impl OperationBuilder { Ok(self) } + fn add_owned_state_det( + self, + name: impl Into, + seal: impl Into>, + state: PersistedState, + ) -> Result { + let name = name.into(); + let type_id = self + .assignments_type(&name, None) + .ok_or(BuilderError::AssignmentNotFound(name.clone()))?; + self.add_owned_state_raw(type_id, seal, state) + } + fn add_owned_state_raw( self, type_id: AssignmentType, seal: impl Into>, - state: PresistedState, + state: PersistedState, ) -> Result { match state { - PresistedState::Void => self.add_rights_raw(type_id, seal), - PresistedState::Amount(value, blinding, tag) => self.add_fungible_state_raw( - type_id, - seal, - RevealedValue::with_blinding(value, blinding, tag), - ), - PresistedState::Data(data, salt) => { + PersistedState::Void => self.add_rights_raw(type_id, seal), + PersistedState::Amount(value, blinding, tag) => { + if self.asset_tag_raw(type_id)? != tag { + return Err(BuilderError::AssetTagInvalid(type_id)); + } + + self.add_fungible_state_raw( + type_id, + seal, + RevealedValue::with_blinding(value, blinding, tag), + ) + } + PersistedState::Data(data, salt) => { self.add_data_raw(type_id, seal, RevealedData::with_salt(data, salt)) } - PresistedState::Attachment(attach, salt) => self.add_attachment_raw( + PersistedState::Attachment(attach, salt) => self.add_attachment_raw( type_id, seal, RevealedAttach::with_salt(attach.id, attach.media_type, salt), @@ -844,7 +962,7 @@ impl OperationBuilder { fn complete( self, - inputs: Option<&TinyOrdMap>, + inputs: Option<&TinyOrdMap>, ) -> (SubSchema, IfacePair, GlobalState, Assignments, TinyOrdMap) { let owned_state = self.fungible.into_iter().map(|(id, vec)| { @@ -871,7 +989,7 @@ impl OperationBuilder { i.iter() .filter(|(out, _)| out.prev_out.ty == id) .map(|(_, ts)| match ts { - PresistedState::Amount(_, blinding, _) => *blinding, + PersistedState::Amount(_, blinding, _) => *blinding, _ => panic!("previous state has invalid type"), }) .collect::>() diff --git a/src/interface/iimpl.rs b/src/interface/iimpl.rs index 52469d53..e7f0154e 100644 --- a/src/interface/iimpl.rs +++ b/src/interface/iimpl.rs @@ -20,6 +20,7 @@ // limitations under the License. use std::fmt::{self, Display, Formatter}; +use std::marker::PhantomData; use std::str::FromStr; use amplify::confinement::{TinyOrdMap, TinyOrdSet}; @@ -34,9 +35,10 @@ use strict_encoding::{FieldName, StrictDumb, TypeName}; use strict_types::encoding::{ StrictDecode, StrictDeserialize, StrictEncode, StrictSerialize, StrictType, }; +use strict_types::TypeLib; use crate::interface::iface::IfaceId; -use crate::interface::{Iface, VerNo}; +use crate::interface::{Iface, IfaceWrapper, VerNo}; use crate::{ReservedBytes, LIB_NAME_RGB_STD}; pub trait SchemaTypeIndex: @@ -300,3 +302,130 @@ impl IfacePair { self.iimpl.transition_type(name) } } + +pub trait IssuerClass { + type IssuingIface: IfaceClass; + + fn schema() -> SubSchema; + fn issue_impl() -> IfaceImpl; + + fn issuer() -> SchemaIssuer { + SchemaIssuer::new(Self::schema(), Self::issue_impl()) + .expect("implementation schema mismatch") + } +} + +pub trait IfaceClass: IfaceWrapper { + fn iface() -> Iface; + fn stl() -> TypeLib; +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error)] +#[display(doc_comments)] +pub enum WrongImplementation { + /// the provided implementation {impl_id} implements interface {actual} + /// instead of {expected} for the schema {schema_id} + InterfaceMismatch { + schema_id: SchemaId, + impl_id: ImplId, + expected: IfaceId, + actual: IfaceId, + }, + + /// the provided implementation {impl_id} uses schema {actual} instead of + /// {expected} + SchemaMismatch { + impl_id: ImplId, + expected: SchemaId, + actual: SchemaId, + }, +} + +#[derive(Getters, Clone, Eq, PartialEq, Debug)] +pub struct IssuerTriplet { + schema: SubSchema, + iface: Iface, + iimpl: IfaceImpl, +} + +impl IssuerTriplet { + #[allow(clippy::result_large_err)] + pub fn new( + iface: Iface, + schema: SubSchema, + iimpl: IfaceImpl, + ) -> Result { + let expected = iface.iface_id(); + let actual = iimpl.iface_id; + + if actual != expected { + return Err(WrongImplementation::InterfaceMismatch { + schema_id: schema.schema_id(), + impl_id: iimpl.impl_id(), + expected, + actual, + }); + } + + let expected = schema.schema_id(); + let actual = iimpl.schema_id; + if actual != expected { + return Err(WrongImplementation::SchemaMismatch { + impl_id: iimpl.impl_id(), + expected, + actual, + }); + } + + // TODO: check schema internal consistency + // TODO: check interface internal consistency + // TODO: check implementation internal consistency + + Ok(Self { + iface, + schema, + iimpl, + }) + } + + #[inline] + pub fn into_split(self) -> (Iface, SubSchema, IfaceImpl) { + (self.iface, self.schema, self.iimpl) + } + + #[inline] + pub fn into_issuer(self) -> (SubSchema, IfaceImpl) { (self.schema, self.iimpl) } +} + +#[derive(Getters, Clone, Eq, PartialEq, Debug)] +pub struct SchemaIssuer { + schema: SubSchema, + iimpl: IfaceImpl, + phantom: PhantomData, +} + +impl SchemaIssuer { + #[allow(clippy::result_large_err)] + pub fn new(schema: SubSchema, iimpl: IfaceImpl) -> Result { + let triplet = IssuerTriplet::new(I::iface(), schema, iimpl)?; + let (_, schema, iimpl) = triplet.into_split(); + + Ok(Self { + schema, + iimpl, + phantom: default!(), + }) + } + + #[inline] + pub fn into_split(self) -> (SubSchema, IfaceImpl) { (self.schema, self.iimpl) } + + pub fn into_triplet(self) -> IssuerTriplet { + let (schema, iimpl) = self.into_split(); + IssuerTriplet { + schema, + iface: I::iface(), + iimpl, + } + } +} diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 4b06193c..4949fdd4 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -32,8 +32,9 @@ pub mod rgb21; pub mod rgb25; mod suppl; mod filters; +pub(crate) mod resolver; -pub use builder::{BuilderError, ContractBuilder, TransitionBuilder}; +pub use builder::{BuilderError, ContractBuilder, TransitionBuilder, TxOutpoint}; pub use contract::{ AllocatedState, AttachAllocation, AttachedState, ContractError, ContractIface, DataAllocation, FungibleAllocation, IfaceOp, IfaceWrapper, OwnedAllocation, RightsAllocation, StateChange, @@ -43,8 +44,11 @@ pub use iface::{ ArgMap, ArgSpec, AssignIface, ExtensionIface, GenesisIface, GlobalIface, Iface, IfaceId, OwnedIface, Req, TransitionIface, ValencyIface, }; -pub use iimpl::{IfaceImpl, IfacePair, ImplId, NamedField, NamedType, SchemaIfaces}; -pub use rgb20::{rgb20, rgb20_stl, AmountChange, Rgb20, LIB_ID_RGB20, LIB_NAME_RGB20}; +pub use iimpl::{ + IfaceClass, IfaceImpl, IfacePair, ImplId, IssuerClass, IssuerTriplet, NamedField, NamedType, + SchemaIfaces, SchemaIssuer, SchemaTypeIndex, WrongImplementation, +}; +pub use rgb20::{AmountChange, Rgb20, LIB_ID_RGB20, LIB_NAME_RGB20}; pub use rgb21::{rgb21, rgb21_stl, Rgb21, LIB_ID_RGB21, LIB_NAME_RGB21}; pub use rgb25::{rgb25, rgb25_stl, Rgb25, LIB_ID_RGB25, LIB_NAME_RGB25}; pub use suppl::{ContractSuppl, OwnedStateSuppl, SupplId, TickerSuppl, VelocityHint}; diff --git a/src/interface/resolver.rs b/src/interface/resolver.rs new file mode 100644 index 00000000..f4e4846d --- /dev/null +++ b/src/interface/resolver.rs @@ -0,0 +1,43 @@ +// RGB standard library for working with smart contracts on 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::convert::Infallible; + +use strict_encoding::StrictDumb; + +use crate::resolvers::ResolveHeight; +use crate::validation::{ResolveWitness, WitnessResolverError}; +use crate::{WitnessAnchor, WitnessId, XAnchor, XPubWitness}; + +pub(crate) struct DumbResolver; + +impl ResolveWitness for DumbResolver { + fn resolve_pub_witness(&self, _: WitnessId) -> Result { + Ok(XPubWitness::strict_dumb()) + } +} + +impl ResolveHeight for DumbResolver { + type Error = Infallible; + fn resolve_anchor(&mut self, _: &XAnchor) -> Result { + Ok(WitnessAnchor::strict_dumb()) + } +} diff --git a/src/interface/rgb20.rs b/src/interface/rgb20.rs index 03d5f0ba..d9c80fbb 100644 --- a/src/interface/rgb20.rs +++ b/src/interface/rgb20.rs @@ -20,20 +20,30 @@ // limitations under the License. use std::collections::HashMap; +use std::str::FromStr; use bp::bc::stl::bp_tx_stl; -use invoice::Amount; -use rgb::WitnessId; +use bp::dbc::Method; +use invoice::{Amount, Precision}; +use rgb::{AltLayer1, AssetTag, BlindingFactor, GenesisSeal, WitnessId}; +use strict_encoding::InvalidIdent; use strict_types::{CompileError, LibBuilder, TypeLib}; use super::{ - AssignIface, GenesisIface, GlobalIface, Iface, IfaceOp, OwnedIface, Req, StateChange, - TransitionIface, VerNo, WitnessFilter, + AssignIface, BuilderError, ContractBuilder, GenesisIface, GlobalIface, Iface, IfaceClass, + IfaceOp, IssuerClass, OwnedIface, Req, SchemaIssuer, StateChange, TransitionIface, VerNo, + WitnessFilter, }; +use crate::containers::Contract; +use crate::interface::builder::TxOutpoint; use crate::interface::{ ArgSpec, ContractIface, FungibleAllocation, IfaceId, IfaceWrapper, OutpointFilter, }; -use crate::stl::{rgb_contract_stl, ContractData, DivisibleAssetSpec, StandardTypes, Timestamp}; +use crate::persistence::PersistedState; +use crate::stl::{ + rgb_contract_stl, Attachment, ContractData, DivisibleAssetSpec, RicardianContract, + StandardTypes, Timestamp, +}; pub const LIB_NAME_RGB20: &str = "RGB20"; /// Strict types id for the library providing data types for RGB20 interface. @@ -71,9 +81,9 @@ fn _rgb20_stl() -> Result { } /// Generates strict type library providing data types for RGB20 interface. -pub fn rgb20_stl() -> TypeLib { _rgb20_stl().expect("invalid strict type RGB20 library") } +fn rgb20_stl() -> TypeLib { _rgb20_stl().expect("invalid strict type RGB20 library") } -pub fn rgb20() -> Iface { +fn rgb20() -> Iface { let types = StandardTypes::with(rgb20_stl()); Iface { @@ -311,7 +321,32 @@ impl IfaceWrapper for Rgb20 { ]); } +impl IfaceClass for Rgb20 { + fn iface() -> Iface { rgb20() } + fn stl() -> TypeLib { rgb20_stl() } +} + impl Rgb20 { + pub fn testnet>( + ticker: &str, + name: &str, + details: Option<&str>, + precision: Precision, + ) -> Result { + PrimaryIssue::testnet::(ticker, name, details, precision) + } + + pub fn testnet_det>( + ticker: &str, + name: &str, + details: Option<&str>, + precision: Precision, + timestamp: Timestamp, + asset_tag: AssetTag, + ) -> Result { + PrimaryIssue::testnet_det::(ticker, name, details, precision, timestamp, asset_tag) + } + pub fn spec(&self) -> DivisibleAssetSpec { let strict_val = &self .0 @@ -391,6 +426,206 @@ impl Rgb20 { } } +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error)] +#[display(doc_comments)] +pub enum AllocationError { + /// contract genesis doesn't support allocating to liquid seals; request + /// liquid support first. + NoLiquidSupport, + /// overflow in the amount of the issued assets: the total amount must not + /// exceed 2^64. + AmountOverflow, +} + +impl From for AllocationError { + fn from(err: BuilderError) -> Self { + match err { + BuilderError::InvalidLayer1(_) => AllocationError::NoLiquidSupport, + _ => panic!("invalid RGB20 schema (assetOwner mismatch)"), + } + } +} + +#[derive(Clone, Debug)] +pub struct PrimaryIssue { + builder: ContractBuilder, + issued: Amount, + contract_data: ContractData, + deterministic: bool, +} + +impl PrimaryIssue { + fn testnet_int( + issuer: SchemaIssuer, + ticker: &str, + name: &str, + details: Option<&str>, + precision: Precision, + timestamp: Timestamp, + ) -> Result { + let spec = DivisibleAssetSpec::with(ticker, name, precision, details)?; + let contract_data = ContractData { + terms: RicardianContract::default(), + media: None, + }; + + let (schema, main_iface_impl) = issuer.into_split(); + let builder = ContractBuilder::testnet(rgb20(), schema, main_iface_impl) + .expect("schema interface mismatch") + .add_global_state("spec", spec) + .expect("invalid RGB20 schema (token specification mismatch)") + .add_global_state("created", timestamp) + .expect("invalid RGB20 schema (creation timestamp mismatch)"); + + Ok(Self { + builder, + contract_data, + issued: Amount::ZERO, + deterministic: false, + }) + } + + pub fn testnet>( + ticker: &str, + name: &str, + details: Option<&str>, + precision: Precision, + ) -> Result { + Self::testnet_int(C::issuer(), ticker, name, details, precision, Timestamp::now()) + } + + pub fn testnet_with( + issuer: SchemaIssuer, + ticker: &str, + name: &str, + details: Option<&str>, + precision: Precision, + ) -> Result { + Self::testnet_int(issuer, ticker, name, details, precision, Timestamp::now()) + } + + pub fn testnet_det>( + ticker: &str, + name: &str, + details: Option<&str>, + precision: Precision, + timestamp: Timestamp, + asset_tag: AssetTag, + ) -> Result { + let mut me = Self::testnet_int(C::issuer(), ticker, name, details, precision, timestamp)?; + me.builder = me + .builder + .add_asset_tag("assetOwner", asset_tag) + .expect("invalid RGB20 schema (assetOwner mismatch)"); + me.deterministic = true; + Ok(me) + } + + pub fn support_liquid(mut self) -> Self { + self.builder = self + .builder + .add_layer1(AltLayer1::Liquid) + .expect("only one layer1 can be added"); + self + } + + pub fn add_terms( + mut self, + contract: &str, + media: Option, + ) -> Result { + let terms = RicardianContract::from_str(contract)?; + self.contract_data = ContractData { terms, media }; + Ok(self) + } + + pub fn allocate( + mut self, + method: Method, + beneficiary: O, + amount: Amount, + ) -> Result { + debug_assert!( + !self.deterministic, + "for creating deterministic contracts please use allocate_det method" + ); + + let beneficiary = beneficiary.map_to_xchain(|outpoint| { + GenesisSeal::new_random(method, outpoint.txid, outpoint.vout) + }); + self.issued + .checked_add_assign(amount) + .ok_or(AllocationError::AmountOverflow)?; + self.builder = + self.builder + .add_fungible_state("assetOwner", beneficiary, amount.value())?; + Ok(self) + } + + pub fn allocate_all( + mut self, + method: Method, + allocations: impl IntoIterator, + ) -> Result { + for (beneficiary, amount) in allocations { + self = self.allocate(method, beneficiary, amount)?; + } + Ok(self) + } + + /// Add asset allocation in a deterministic way. + pub fn allocate_det( + mut self, + method: Method, + beneficiary: O, + seal_blinding: u64, + amount: Amount, + amount_blinding: BlindingFactor, + ) -> Result { + debug_assert!( + !self.deterministic, + "to add asset allocation in deterministic way the contract builder has to be created \ + using `*_det` constructor" + ); + + let tag = self + .builder + .asset_tag("assetOwner") + .expect("internal library error: asset tag is unassigned"); + let beneficiary = beneficiary.map_to_xchain(|outpoint| { + GenesisSeal::with_blinding(method, outpoint.txid, outpoint.vout, seal_blinding) + }); + self.issued + .checked_add_assign(amount) + .ok_or(AllocationError::AmountOverflow)?; + self.builder = self.builder.add_owned_state_det( + "assetOwner", + beneficiary, + PersistedState::Amount(amount, amount_blinding, tag), + )?; + Ok(self) + } + + // TODO: implement when bulletproofs are supported + /* + pub fn conceal_allocations(mut self) -> Self { + + } + */ + + #[allow(clippy::result_large_err)] + pub fn issue_contract(self) -> Result { + self.builder + .add_global_state("issuedSupply", self.issued) + .expect("invalid RGB20 schema (issued supply mismatch)") + .add_global_state("data", self.contract_data) + .expect("invalid RGB20 schema (contract data mismatch)") + .issue_contract() + } + + // TODO: Add secondary issuance and other methods +} + #[cfg(test)] mod test { use super::*; diff --git a/src/persistence/hoard.rs b/src/persistence/hoard.rs index b4dabd1e..bee20ad9 100644 --- a/src/persistence/hoard.rs +++ b/src/persistence/hoard.rs @@ -36,7 +36,7 @@ use strict_encoding::TypeName; use crate::accessors::{MergeReveal, MergeRevealError}; use crate::containers::{Cert, Consignment, ContentId, ContentSigs}; use crate::interface::{ - rgb20, rgb21, rgb25, ContractSuppl, Iface, IfaceId, IfacePair, SchemaIfaces, + rgb21, rgb25, ContractSuppl, Iface, IfaceClass, IfaceId, IfacePair, Rgb20, SchemaIfaces, }; use crate::persistence::{InventoryError, Stash, StashError, StashInconsistency}; use crate::LIB_NAME_RGB_STD; @@ -86,7 +86,7 @@ pub struct Hoard { impl Hoard { pub fn preset() -> Self { - let rgb20 = rgb20(); + let rgb20 = Rgb20::iface(); let rgb20_id = rgb20.iface_id(); let rgb21 = rgb21(); let rgb21_id = rgb21.iface_id(); diff --git a/src/persistence/inventory.rs b/src/persistence/inventory.rs index 48ef9734..05979bef 100644 --- a/src/persistence/inventory.rs +++ b/src/persistence/inventory.rs @@ -48,7 +48,7 @@ use crate::interface::{ }; use crate::persistence::hoard::ConsumeError; use crate::persistence::stash::StashInconsistency; -use crate::persistence::{PresistedState, Stash, StashError}; +use crate::persistence::{PersistedState, Stash, StashError}; use crate::resolvers::ResolveHeight; #[derive(Debug, Display, Error, From)] @@ -566,7 +566,7 @@ pub trait Inventory: Deref { &self, contract_id: ContractId, outpoints: impl IntoIterator>, - ) -> Result, InventoryError>; + ) -> Result, InventoryError>; fn store_seal_secret( &mut self, @@ -827,9 +827,9 @@ pub trait Inventory: Deref { let seal = output_for_assignment(contract_id, opout.ty)?; state.update_blinding(pedersen_blinder(contract_id, assignment_id)); main_builder = main_builder.add_owned_state_raw(opout.ty, seal, state)?; - } else if let PresistedState::Amount(value, _, _) = state { + } else if let PersistedState::Amount(value, _, _) = state { sum_inputs += value; - } else if let PresistedState::Data(value, _) = state { + } else if let PersistedState::Data(value, _) = state { data_inputs.push(value); } } @@ -882,7 +882,7 @@ pub trait Inventory: Deref { // 3. Prepare other transitions // Enumerate state let mut spent_state = - HashMap::>::new(); + HashMap::>::new(); for output in prev_outputs { for id in self.contracts_by_outputs([output])? { if id == contract_id { @@ -902,7 +902,7 @@ pub trait Inventory: Deref { for ((opout, output), mut state) in opouts { let seal = output_for_assignment(id, opout.ty)?; outputs.push(output); - if let PresistedState::Amount(_, ref mut blinding, _) = state { + if let PersistedState::Amount(_, ref mut blinding, _) = state { *blinding = pedersen_blinder(id, opout.ty); } blank_builder = blank_builder diff --git a/src/persistence/mod.rs b/src/persistence/mod.rs index 19609705..3b415702 100644 --- a/src/persistence/mod.rs +++ b/src/persistence/mod.rs @@ -44,5 +44,5 @@ pub use inventory::{ InventoryInconsistency, }; pub use stash::{Stash, StashError, StashInconsistency}; -pub use state::PresistedState; +pub use state::PersistedState; pub use stock::Stock; diff --git a/src/persistence/state.rs b/src/persistence/state.rs index 63980c1a..400e8a19 100644 --- a/src/persistence/state.rs +++ b/src/persistence/state.rs @@ -25,20 +25,20 @@ use rgb::{AssetTag, BlindingFactor, DataState}; use crate::interface::AttachedState; #[derive(Clone, Eq, PartialEq, Debug, Hash)] -pub enum PresistedState { +pub enum PersistedState { Void, Amount(Amount, BlindingFactor, AssetTag), Data(DataState, u128), Attachment(AttachedState, u64), } -impl PresistedState { +impl PersistedState { pub(super) fn update_blinding(&mut self, blinding: BlindingFactor) { match self { - PresistedState::Void => {} - PresistedState::Amount(_, b, _) => *b = blinding, - PresistedState::Data(_, _) => {} - PresistedState::Attachment(_, _) => {} + PersistedState::Void => {} + PersistedState::Amount(_, b, _) => *b = blinding, + PersistedState::Data(_, _) => {} + PersistedState::Attachment(_, _) => {} } } } diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index bfdbc27f..ea3779ed 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -39,7 +39,7 @@ use crate::interface::{ContractIface, Iface, IfaceId, IfaceImpl, IfacePair, Sche use crate::persistence::hoard::ConsumeError; use crate::persistence::inventory::{DataError, IfaceImplError, InventoryInconsistency}; use crate::persistence::{ - Hoard, Inventory, InventoryDataError, InventoryError, PresistedState, Stash, StashInconsistency, + Hoard, Inventory, InventoryDataError, InventoryError, PersistedState, Stash, StashInconsistency, }; use crate::resolvers::ResolveHeight; use crate::LIB_NAME_RGB_STD; @@ -643,7 +643,7 @@ impl Inventory for Stock { &self, contract_id: ContractId, outputs: impl IntoIterator>, - ) -> Result, InventoryError> { + ) -> Result, InventoryError> { let outputs = outputs .into_iter() .map(|o| o.into()) @@ -660,7 +660,7 @@ impl Inventory for Stock { if outputs.contains(&item.seal.into()) { res.insert( (item.opout, item.seal), - PresistedState::Amount( + PersistedState::Amount( item.state.value.into(), item.state.blinding, item.state.tag, @@ -673,14 +673,14 @@ impl Inventory for Stock { if outputs.contains(&item.seal.into()) { res.insert( (item.opout, item.seal), - PresistedState::Data(item.state.value.clone(), item.state.salt), + PersistedState::Data(item.state.value.clone(), item.state.salt), ); } } for item in history.rights() { if outputs.contains(&item.seal.into()) { - res.insert((item.opout, item.seal), PresistedState::Void); + res.insert((item.opout, item.seal), PersistedState::Void); } } @@ -688,7 +688,7 @@ impl Inventory for Stock { if outputs.contains(&item.seal.into()) { res.insert( (item.opout, item.seal), - PresistedState::Attachment(item.state.clone().into(), item.state.salt), + PersistedState::Attachment(item.state.clone().into(), item.state.salt), ); } } diff --git a/stl/src/main.rs b/stl/src/main.rs index 139409f3..f62982cc 100644 --- a/stl/src/main.rs +++ b/stl/src/main.rs @@ -20,7 +20,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use rgbstd::interface::{rgb20_stl, rgb21_stl, rgb25_stl}; +use rgbstd::interface::{rgb21_stl, rgb25_stl, IfaceClass, Rgb20}; use rgbstd::stl::{rgb_contract_stl, rgb_std_stl}; use strict_types::parse_args; @@ -36,13 +36,13 @@ fn main() { " Description: Types for writing RGB contracts and interfaces Author: Dr Maxim Orlovsky - Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. + Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. License: Apache-2.0", ), ) .expect("unable to write to the file"); - rgb20_stl() + Rgb20::stl() .serialize( format, dir.as_ref(), @@ -51,7 +51,7 @@ fn main() { " Description: Types for RGB20 interface Author: Dr Maxim Orlovsky - Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. + Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. License: Apache-2.0", ), ) @@ -66,7 +66,7 @@ fn main() { " Description: Types for RGB21 interface Author: Dr Maxim Orlovsky - Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. + Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. License: Apache-2.0", ), ) @@ -81,7 +81,7 @@ fn main() { " Description: Types for RGB25 interface Author: Zoe FaltibĂ  - Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. + Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. License: Apache-2.0", ), ) @@ -96,7 +96,7 @@ fn main() { " Description: RGB standard library Author: Dr Maxim Orlovsky - Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. + Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. License: Apache-2.0", ), )