diff --git a/Cargo.lock b/Cargo.lock index 8af91da5..6bd109fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aluvm" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fd60657e5d59425e897145c167b2250238aaeaa825a6741249d120b87871bf" +checksum = "e624a600eaf54f24da48e42604ffb0fbd543808a078e5081a9441243077233df" dependencies = [ "amplify", "baid58", @@ -23,12 +23,12 @@ dependencies = [ [[package]] name = "amplify" -version = "4.0.1" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4707ab08f19a25ba492cbf61713591b7f022b54ee188f35457e6de22f367df4a" +checksum = "8629db306c0bbeb0a402e2918bdcf0026b5ddb24c46460f3bf5410b350d98710" dependencies = [ "amplify_apfloat", - "amplify_derive 3.0.1", + "amplify_derive", "amplify_num", "amplify_syn", "ascii", @@ -36,7 +36,7 @@ dependencies = [ "serde_json", "serde_yaml", "stringly_conversions", - "toml 0.5.11", + "toml", "wasm-bindgen", ] @@ -52,21 +52,9 @@ dependencies = [ [[package]] name = "amplify_derive" -version = "3.0.1" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87df0f28e6eb1f2d355f29ba6793fa9ca643967528609608d5cbd70bd68f9d1" -dependencies = [ - "amplify_syn", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "amplify_derive" -version = "4.0.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c4835e964725149d7961ec5af2ca1302f6f68c8c738b4acb06185f596c3333" +checksum = "759dcbfaf94d838367a86d493ec34ccc8aa6fe365cb7880d6bf89006de24d9c1" dependencies = [ "amplify_syn", "proc-macro2", @@ -156,15 +144,9 @@ checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" [[package]] name = "base64" -version = "0.13.1" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "base85" @@ -182,17 +164,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] -name = "bitcoin" -version = "0.30.1" +name = "bitcoin-internals" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e99ff7289b20a7385f66a0feda78af2fc119d28fb56aea8886a9cd0a4abdd75" -dependencies = [ - "bech32", - "bitcoin-private", - "bitcoin_hashes", - "hex_lit", - "secp256k1", -] +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" [[package]] name = "bitcoin-private" @@ -202,11 +177,12 @@ checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" [[package]] name = "bitcoin_hashes" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" dependencies = [ - "bitcoin-private", + "bitcoin-internals", + "hex-conservative", ] [[package]] @@ -217,16 +193,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "blake3" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", - "digest", ] [[package]] @@ -239,61 +214,62 @@ dependencies = [ ] [[package]] -name = "bp-core" -version = "0.10.9" +name = "bp-consensus" +version = "0.10.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accdf591895f370bb02f0e332b5a26d6124354b058801ef4b155d781ed4eb0d0" +checksum = "0d7b87840e5fc65bcbcd3881e0a0150ecef4a9b18b1356eb7a8a9adc85280c63" dependencies = [ "amplify", - "bp-dbc", - "bp-primitives", - "bp-seals", + "chrono", "commit_verify", + "secp256k1", "serde", - "single_use_seals", "strict_encoding", "strict_types", ] [[package]] -name = "bp-dbc" -version = "0.10.9" +name = "bp-core" +version = "0.10.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfc6323f4f8c78e4d001c2e4edf176f04f5fb41c319ed9e27431ab34f25c1750" +checksum = "3a8b5219d96064b5d277c166fd5321ce6ee3e8a74e50bf2281d47726f365ead4" dependencies = [ "amplify", - "base85", - "bp-primitives", + "bp-consensus", + "bp-dbc", + "bp-seals", "commit_verify", - "secp256k1", "serde", + "single_use_seals", "strict_encoding", + "strict_types", ] [[package]] -name = "bp-primitives" -version = "0.10.7" +name = "bp-dbc" +version = "0.10.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b450c7dc09b5379d52c0a7980e5041339dea9753b5810afd397d67480d29b605" +checksum = "e265b111f61acb39cf36778c4da9a3d3c49fcc7a7e4116fd40ab250d598b1280" dependencies = [ "amplify", + "base85", + "bp-consensus", "commit_verify", "secp256k1", "serde", "strict_encoding", - "strict_types", ] [[package]] name = "bp-seals" -version = "0.10.9" +version = "0.10.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980cb7c5e1bebba10dc65c7c192ba58d254dfb3db7abb7ff10159886c35a17ba" +checksum = "8ccb60735209233ece5927a5c66355037af8479104b5ff55371ae4a0f53c96b2" dependencies = [ "amplify", "baid58", + "bp-consensus", "bp-dbc", - "bp-primitives", "commit_verify", "rand", "serde", @@ -301,23 +277,42 @@ dependencies = [ "strict_encoding", ] +[[package]] +name = "bp-std" +version = "0.10.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8098ada83a67537e36620857c16630bc4df32a50113650555b9a287eb0a64fe0" +dependencies = [ + "amplify", + "bech32", + "bitcoin_hashes", + "bp-consensus", + "bp-core", + "commit_verify", + "indexmap 2.0.2", + "serde", +] + [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -325,20 +320,30 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", - "time 0.1.45", "wasm-bindgen", - "winapi", + "windows-targets", ] [[package]] @@ -356,13 +361,14 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caa8114b3ff20947176c8cbfd1e84e56649501eed4e33ba9205c70374b2615ae" +checksum = "91d9d6e86f6cec8d4af19a0e418bac9cb266a6dc70660bcdcdac1e0fa924e0d1" dependencies = [ "amplify", "commit_encoding_derive", "rand", + "ripemd", "serde", "sha2", "strict_encoding", @@ -437,7 +443,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -448,18 +454,29 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "deranged" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" dependencies = [ "serde", ] +[[package]] +name = "descriptors" +version = "0.10.0-BP-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6105e8317f28ac87e2a30cd4f8fcd1a4fc330e63b0faf55d93cf2041fc12dd5" +dependencies = [ + "amplify", + "bp-std", + "indexmap 2.0.2", +] + [[package]] name = "digest" version = "0.10.7" @@ -468,7 +485,6 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", - "subtle", ] [[package]] @@ -511,7 +527,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -532,9 +548,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" [[package]] name = "heck" @@ -549,10 +565,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hex_lit" +name = "hex-conservative" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" [[package]] name = "iana-time-zone" @@ -596,12 +612,13 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.1", + "serde", ] [[package]] @@ -627,21 +644,21 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "mime" @@ -661,9 +678,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -694,18 +711,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -742,9 +759,8 @@ dependencies = [ [[package]] name = "rgb-core" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4208ae00f665554fa9195c0d54e7627f70b3202490e9549c26f731eda4922943" +version = "0.10.8" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.10#f9dc0afb736c7520c57e229438c3e9453aab9c9a" dependencies = [ "aluvm", "amplify", @@ -762,47 +778,57 @@ dependencies = [ ] [[package]] -name = "rgb-std" -version = "0.10.7" +name = "rgb-invoice" +version = "0.11.0-alpha" dependencies = [ "amplify", "baid58", - "base85", - "bp-core", + "bp-std", "chrono", - "commit_verify", + "fluent-uri", "getrandom", + "indexmap 2.0.2", + "percent-encoding", "rand", - "rgb-core", - "serde", + "rgb-std", "strict_encoding", - "strict_types", "wasm-bindgen", "wasm-bindgen-test", ] [[package]] -name = "rgb-wallet" -version = "0.10.7" +name = "rgb-std" +version = "0.11.0-alpha" dependencies = [ "amplify", "baid58", - "bitcoin", + "base85", "bp-core", + "bp-std", + "cfg_eval", "chrono", "commit_verify", - "fluent-uri", + "descriptors", "getrandom", - "indexmap 1.9.3", - "percent-encoding", + "indexmap 2.0.2", "rand", "rgb-core", - "rgb-std", + "serde", + "serde_with", "strict_encoding", + "strict_types", "wasm-bindgen", "wasm-bindgen-test", ] +[[package]] +name = "rgb-stl" +version = "0.11.0-alpha" +dependencies = [ + "rgb-std", + "strict_types", +] + [[package]] name = "ripemd" version = "0.1.3" @@ -830,7 +856,6 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ - "bitcoin_hashes", "rand", "secp256k1-sys", "serde", @@ -847,9 +872,9 @@ dependencies = [ [[package]] name = "secp256k1-zkp" -version = "0.8.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c07a95044ad86d2bfde4bb9bc99728aad3b311aa4fabea9db3b670846224186" +checksum = "026efcdacb95ee6aae5cc19144dc1549973eac36a4972700c28493de1ee5d69f" dependencies = [ "bitcoin-private", "rand", @@ -870,29 +895,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.180" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.180" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -920,30 +945,31 @@ dependencies = [ [[package]] name = "serde_with" -version = "2.3.3" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237" dependencies = [ - "base64 0.13.1", + "base64", "chrono", "hex", "indexmap 1.9.3", + "indexmap 2.0.2", "serde", "serde_json", "serde_with_macros", - "time 0.3.24", + "time", ] [[package]] name = "serde_with_macros" -version = "2.3.3" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -952,7 +978,7 @@ version = "0.9.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.0.2", "itoa", "ryu", "serde", @@ -961,9 +987,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -972,18 +998,18 @@ dependencies = [ [[package]] name = "single_use_seals" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae7f7cb6a68cfc99674a70a47ab790c6ede965107cd0823ed814b5e73b3bee2" +checksum = "ed7655b4b597fca10d2cf7579d3dfee1987a45342bdeecf90cab5affec1c7197" dependencies = [ - "amplify_derive 4.0.0-alpha.6", + "amplify_derive", ] [[package]] name = "strict_encoding" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b1c91b79e62afc09025d828fa0b8dbf4105513de38f126a017919c09bca472" +checksum = "ab7b75b4af0aff9dd97b68df262bf0e807b7d007cc860fa217943f898a05a5ab" dependencies = [ "amplify", "half", @@ -993,9 +1019,9 @@ dependencies = [ [[package]] name = "strict_encoding_derive" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5adae55367464f5a229bfd539682c94f870b98a220be6e61dc43f85d612e7e" +checksum = "37064ec285e2a633465eb525c8698eea51373dee889fe310e0d32df8343e7f4f" dependencies = [ "amplify_syn", "heck", @@ -1006,22 +1032,21 @@ dependencies = [ [[package]] name = "strict_types" -version = "1.6.0" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a6654c43ed02891b249730856ad6b866fd85d1008aad51b30bd68812798427" +checksum = "d10cc45e67d452cfe0d87d4714c3250190d97479af3502bbd823651bfe0f505f" dependencies = [ "amplify", "baid58", - "base64 0.21.2", + "base64", "half", - "indexmap 1.9.3", + "indexmap 2.0.2", "serde", "serde_json", - "serde_with", "serde_yaml", "sha2", "strict_encoding", - "toml 0.7.6", + "toml", ] [[package]] @@ -1040,12 +1065,6 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - [[package]] name = "syn" version = "1.0.109" @@ -1059,9 +1078,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -1070,40 +1089,29 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "time" -version = "0.1.45" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "time" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b" +checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" dependencies = [ "deranged", "itoa", @@ -1114,33 +1122,24 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] [[package]] name = "toml" -version = "0.5.11" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "toml" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" dependencies = [ "serde", "serde_spanned", @@ -1159,11 +1158,11 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.0.2", "serde", "serde_spanned", "toml_datetime", @@ -1172,15 +1171,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unsafe-libyaml" @@ -1194,12 +1193,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1227,7 +1220,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -1261,7 +1254,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1306,28 +1299,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows" version = "0.48.0" @@ -1339,9 +1310,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1354,51 +1325,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.2" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd122eb777186e60c3fdf765a58ac76e41c582f1f535fbf3314434c6b58f3f7" +checksum = "037711d82167854aff2018dfd193aa0fef5370f456732f0d5a0c59b0f1b4b907" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index b95b6c2f..6f126ff8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,14 @@ [workspace] members = [ "std", - ".", + "invoice", + "stl" ] default-members = [ "std", - "." + "invoice" ] +resolver = "2" [workspace.package] authors = ["Dr Maxim Orlovsky "] @@ -17,62 +19,17 @@ edition = "2021" license = "Apache-2.0" [workspace.dependencies] -amplify = "4.0.1" +amplify = "4.5.0" baid58 = "0.4.4" -strict_encoding = "2.5.0" -strict_types = "1.6.0" -commit_verify = { version = "0.10.5", features = ["stl"] } -bp-core = { version = "0.10.8", features = ["stl"] } -rgb-core = { version = "0.10.7", features = ["stl"] } - -[package] -name = "rgb-wallet" -version = "0.10.7" -description = "RGB wallet library for smart contracts on Bitcoin & Lightning network" -keywords = ["bitcoin", "lightning", "rgb", "smart-contracts", "lnp-bp"] -categories = ["cryptography::cryptocurrencies"] -authors = { workspace = true } -repository = { workspace = true } -homepage = { workspace = true } -edition = { workspace = true } -license = { workspace = true } -rust-version = { workspace = true } -readme = "README.md" -exclude = [".github", "std"] - -[lib] -name = "rgbwallet" -crate-type = ["cdylib", "rlib"] # We need this for WASM - -[dependencies] -amplify = { workspace = true } -baid58 = { workspace = true } -commit_verify = { workspace = true } -strict_encoding = { workspace = true } -# descriptor-wallet = "0.10.0-alpha.1" -bp-core = { workspace = true } -rgb-core = { workspace = true } -rgb-std = { version = "0.10.7", path = "std" } -fluent-uri = "0.1.4" -indexmap = "1.9.2" -# TODO: This dependencies should be replaced with psbt package -bitcoin = "0.30.0" -chrono = "0.4.24" -percent-encoding = "2.2.0" - -[features] -default = [] -all = ["fs", "serde"] -serde = ["rgb-std/serde", "rgb-core/serde"] -fs = ["rgb-std/fs"] - -[target.'cfg(target_arch = "wasm32")'.dependencies] -wasm-bindgen = "0.2" -rand = { version = "0.8.4", optional = true } -getrandom = { version = "0.2", features = ["js"] } - -[target.'cfg(target_arch = "wasm32")'.dev-dependencies] -wasm-bindgen-test = "0.3" - -[package.metadata.docs.rs] -features = [ "all" ] +strict_encoding = "2.6.1" +strict_types = "1.6.3" +commit_verify = { version = "0.10.6", features = ["stl"] } +bp-core = { version = "0.10.11", features = ["stl"] } +bp-std = "0.10.0-beta.1" +rgb-core = { version = "0.10.8", features = ["stl"] } +cfg_eval = "0.1.2" +serde_crate = { package = "serde", version = "1" } +serde_with = "3.1.0" + +[patch.crates-io] +rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "v0.10" } diff --git a/invoice/Cargo.toml b/invoice/Cargo.toml new file mode 100644 index 00000000..bc7f11f3 --- /dev/null +++ b/invoice/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "rgb-invoice" +version = "0.11.0-alpha" +description = "RGB smart contract invoicing library" +keywords = ["bitcoin", "invoices", "rgb", "smart-contracts", "lnp-bp"] +categories = ["cryptography::cryptocurrencies"] +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +rust-version = { workspace = true } +readme = "../README.md" + +[lib] +name = "rgbinvoice" +crate-type = ["cdylib", "rlib"] # We need this for WASM + +[dependencies] +amplify = { workspace = true } +baid58 = { workspace = true } +strict_encoding = { workspace = true } +bp-std = { workspace = true } +rgb-std = { version = "0.11.0-alpha", path = "../std" } +indexmap = "2.0.0" +fluent-uri = "0.1.4" +chrono = "0.4.24" +percent-encoding = "2.2.0" + +[target.'cfg(target_arch = "wasm32")'.dependencies] +wasm-bindgen = "0.2" +rand = { version = "0.8.4", optional = true } +getrandom = { version = "0.2", features = ["js"] } + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test = "0.3" + +[package.metadata.docs.rs] +features = [ "all" ] diff --git a/src/invoice/builder.rs b/invoice/src/builder.rs similarity index 96% rename from src/invoice/builder.rs rename to invoice/src/builder.rs index 3898bd19..85c182d0 100644 --- a/src/invoice/builder.rs +++ b/invoice/src/builder.rs @@ -1,4 +1,4 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network +// RGB smart contract invoicing library // // SPDX-License-Identifier: Apache-2.0 // @@ -21,10 +21,9 @@ use std::str::FromStr; -use rgb::ContractId; -use rgbstd::interface::TypedState; -use rgbstd::stl::Precision; -use rgbstd::Chain; +use rgb::interface::TypedState; +use rgb::stl::Precision; +use rgb::{Chain, ContractId}; use super::{Beneficiary, RgbInvoice, RgbTransport, TransportParseError}; diff --git a/src/invoice/invoice.rs b/invoice/src/invoice.rs similarity index 91% rename from src/invoice/invoice.rs rename to invoice/src/invoice.rs index 0ac55438..a320dc90 100644 --- a/src/invoice/invoice.rs +++ b/invoice/src/invoice.rs @@ -1,4 +1,4 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network +// RGB smart contract invoicing library // // SPDX-License-Identifier: Apache-2.0 // @@ -19,11 +19,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use bitcoin::Address; +use bpstd::Address; use indexmap::IndexMap; -use rgb::{AttachId, ContractId, SecretSeal}; -use rgbstd::interface::TypedState; -use rgbstd::Chain; +use rgb::interface::TypedState; +use rgb::{AttachId, Chain, ContractId, SecretSeal}; use strict_encoding::{FieldName, TypeName}; #[derive(Clone, Eq, PartialEq, Hash, Debug)] diff --git a/src/invoice/mod.rs b/invoice/src/lib.rs similarity index 88% rename from src/invoice/mod.rs rename to invoice/src/lib.rs index e98c10e4..4c48ff37 100644 --- a/src/invoice/mod.rs +++ b/invoice/src/lib.rs @@ -1,4 +1,4 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network +// RGB smart contract invoicing library // // SPDX-License-Identifier: Apache-2.0 // @@ -19,6 +19,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[macro_use] +extern crate amplify; +#[macro_use] +extern crate strict_encoding; + mod invoice; mod parse; mod builder; diff --git a/src/invoice/parse.rs b/invoice/src/parse.rs similarity index 97% rename from src/invoice/parse.rs rename to invoice/src/parse.rs index 5aa2cb86..a4bda613 100644 --- a/src/invoice/parse.rs +++ b/invoice/src/parse.rs @@ -1,4 +1,4 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network +// RGB smart contract invoicing library // // SPDX-License-Identifier: Apache-2.0 // @@ -23,14 +23,13 @@ use std::fmt::{self, Debug, Display, Formatter}; use std::num::ParseIntError; use std::str::FromStr; -use bitcoin::{Address, Network}; -use bp::Chain; +use bpstd::{Address, AddressNetwork}; use fluent_uri::enc::EStr; use fluent_uri::Uri; use indexmap::IndexMap; use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; -use rgb::{ContractId, SecretSeal}; -use rgbstd::interface::TypedState; +use rgb::interface::TypedState; +use rgb::{Chain, ContractId, SecretSeal}; use strict_encoding::{InvalidIdent, TypeName}; use super::{Beneficiary, RgbInvoice, RgbTransport}; @@ -110,8 +109,8 @@ pub enum InvoiceParseError { Beneficiary(String), #[display(doc_comments)] - /// network {0} is not supported. - UnsupportedNetwork(Network), + /// network {0:?} is not supported. + UnsupportedNetwork(AddressNetwork), #[from] Num(ParseIntError), @@ -298,13 +297,11 @@ impl FromStr for RgbInvoice { (Ok(seal), Err(_)) => Beneficiary::BlindedSeal(seal), (Err(_), Ok(addr)) => { chain = Some(match addr.network { - Network::Bitcoin => Chain::Bitcoin, - Network::Testnet => Chain::Testnet3, - Network::Signet => Chain::Signet, - Network::Regtest => Chain::Regtest, - unknown => return Err(InvoiceParseError::UnsupportedNetwork(unknown)), + AddressNetwork::Mainnet => Chain::Bitcoin, + AddressNetwork::Testnet => Chain::Testnet3, + AddressNetwork::Regtest => Chain::Regtest, }); - Beneficiary::WitnessUtxo(addr.assume_checked()) + Beneficiary::WitnessUtxo(addr) } (Err(_), Err(_)) => { return Err(InvoiceParseError::Beneficiary(beneficiary_str.to_owned())); diff --git a/psbt/Cargo.toml b/psbt/Cargo.toml new file mode 100644 index 00000000..8592e4af --- /dev/null +++ b/psbt/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "rgb-psbt" +version = "0.11.0-alpha" +description = "RGB smart contract invoicing library" +keywords = ["bitcoin", "invoices", "rgb", "smart-contracts", "lnp-bp"] +categories = ["cryptography::cryptocurrencies"] +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +rust-version = { workspace = true } +readme = "../README.md" + +[lib] +name = "rgbpsbt" +crate-type = ["cdylib", "rlib"] # We need this for WASM + +[dependencies] +amplify = { workspace = true } +baid58 = { workspace = true } +bp-std = { workspace = true } +psbt = "0.11.0" +rgb-std = { version = "0.11.0-alpha", path = "../std" } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +wasm-bindgen = "0.2" +rand = { version = "0.8.4", optional = true } +getrandom = { version = "0.2", features = ["js"] } + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test = "0.3" + +[package.metadata.docs.rs] +features = [ "all" ] diff --git a/psbt/src/lib.rs b/psbt/src/lib.rs new file mode 100644 index 00000000..7d12d9af --- /dev/null +++ b/psbt/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/pay.rs b/psbt/src/pay.rs similarity index 100% rename from src/pay.rs rename to psbt/src/pay.rs diff --git a/src/psbt/rgb.rs b/psbt/src/rgb.rs similarity index 100% rename from src/psbt/rgb.rs rename to psbt/src/rgb.rs diff --git a/scripts/typelib.sh b/scripts/typelib.sh index 34d2fe78..cb21bb8d 100755 --- a/scripts/typelib.sh +++ b/scripts/typelib.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -cargo run --bin rgb-stl -- --sty -cargo run --bin rgb-stl -- --stl -cargo run --bin rgb-stl -- --sta +cargo run -p rgb-stl --bin rgb-stl -- --sty +cargo run -p rgb-stl --bin rgb-stl -- --stl +cargo run -p rgb-stl --bin rgb-stl -- --sta diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index e2e0f858..00000000 --- a/src/lib.rs +++ /dev/null @@ -1,90 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// 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. - -//! Library provides three main procedures: -//! -//! ## 1. PSBT-based state transition construction. -//! -//! Given PSBT-originating set of outpoints the procedure creates all required -//! state transitions for all contracts, adding necessary information to PSBT -//! for constructing bundles and tapret proofs. The actual state transitions are -//! saved into the stash even before witness transactions are mined. They may be -//! also put into PSBT, if needed for the hardware signers. -//! -//! ## 2. PSBT-based finalization. -//! -//! Procedure takes PSBT with all information for constructing transition -//! bundles and taprets and -//! a) generates final tapret commitment; -//! b) creates consignment for the main transfer. -//! -//! ## 3. Descriptor-based contract state. -//! -//! Checks descriptor UTXO set and updates contract, removing outdated outputs. -//! For instance, after consignment creation, a new state transition is already -//! present in the contract state, even before the witness transaction is mined. -//! Descriptor filtering of the contract state will show a valid result, since -//! a new state without mined witness will not be displayed. Once the witness -//! gets mined, a new state appears, and previous state gets invalidated since -//! it no longer assigned to an unspent transaction output. - -#![deny( - non_upper_case_globals, - non_camel_case_types, - non_snake_case, - unused_mut, - unused_imports, - dead_code, - //missing_docs -)] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] - -#[macro_use] -extern crate amplify; -#[macro_use] -extern crate strict_encoding; -pub extern crate bitcoin; - -mod invoice; -mod pay; -pub mod psbt; - -pub use invoice::{ - Beneficiary, InvoiceParseError, InvoiceState, RgbInvoice, RgbInvoiceBuilder, RgbTransport, - TransportParseError, -}; -pub use pay::{InventoryWallet, PayError}; - -/// BIP32 derivation index for outputs which may contain assigned RGB state. -pub const RGB_NATIVE_DERIVATION_INDEX: u32 = 9; -/// BIP32 derivation index for outputs which are tweaked with Tapret commitment -/// and may also optionally contain assigned RGB state. -pub const RGB_TAPRET_DERIVATION_INDEX: u32 = 10; - -// 1. Construct main state transition with transition builder -// -- shortcut using invoice to do that construction (like .with_invoice()) -// -- have a construction for the "remaining state" assigned to a seal -// prototype. -// 2. Add that state transition to PSBT -// -- add change by checking change PSBT flag and assigning remaining state to -// that output -// 3. Extract from PSBT all spent prevouts and construct blank state transitions -// for each one of them; embed them into PSBT diff --git a/src/psbt/dbc.rs b/src/psbt/dbc.rs deleted file mode 100644 index a4bbf4d6..00000000 --- a/src/psbt/dbc.rs +++ /dev/null @@ -1,169 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// 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 amplify::num::u5; -use amplify::RawArray; -use bitcoin::hashes::Hash; -use bitcoin::psbt::Psbt; -use bitcoin::secp256k1::SECP256K1; -use bitcoin::taproot::{TapTree, TaprootBuilder, TaprootBuilderError}; -use bitcoin::ScriptBuf; -use bp::dbc::tapret::{TapretCommitment, TapretPathProof, TapretProof}; -use bp::dbc::Proof; -use bp::seals::txout::CloseMethod; -use bp::TapScript; -use commit_verify::{mpc, CommitVerify, CommitmentId, TryCommitVerify}; -use rgb::Anchor; - -use crate::psbt::lnpbp4::OutputLnpbp4; -use crate::psbt::opret::OutputOpret; -use crate::psbt::tapret::{OutputTapret, TapretKeyError}; -use crate::psbt::{Lnpbp4PsbtError, OpretKeyError, PSBT_OUT_LNPBP4_MIN_TREE_DEPTH}; - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum DbcPsbtError { - /// Using non-empty taptree is not supported in RGB v0.10. Please update. - TapTreeNonEmpty, - - /// taproot output doesn't specify internal key. - NoInternalKey, - - /// none of the outputs is market as a commitment host. - NoHostOutput, - - /// multiple commitment outputs are found - MultipleCommitmentHosts, - - /// commitment method {0} is not supported yet. Please update. - MethodUnsupported(CloseMethod), - - #[from] - #[display(inner)] - Mpc(mpc::Error), - - #[from] - #[display(inner)] - Lnpbp4Psbt(Lnpbp4PsbtError), - - #[from] - #[display(inner)] - TapretKey(TapretKeyError), - - #[from] - #[display(inner)] - OpretKey(OpretKeyError), - - #[from] - #[display(inner)] - TaprootBuilder(TaprootBuilderError), -} - -pub trait PsbtDbc { - fn dbc_conclude( - &mut self, - method: CloseMethod, - ) -> Result, DbcPsbtError>; -} - -impl PsbtDbc for Psbt { - fn dbc_conclude( - &mut self, - method: CloseMethod, - ) -> Result, DbcPsbtError> { - if self - .outputs - .iter() - .filter(|output| output.is_tapret_host() | output.is_opret_host()) - .count() > - 1 - { - return Err(DbcPsbtError::MultipleCommitmentHosts); - } - - let (vout, output) = self - .outputs - .iter_mut() - .enumerate() - .find(|(_, output)| { - (output.is_tapret_host() && method == CloseMethod::TapretFirst) | - (output.is_opret_host() && method == CloseMethod::OpretFirst) - }) - .ok_or(DbcPsbtError::NoHostOutput)?; - let txout = &mut self.unsigned_tx.output[vout]; - - let messages = output.lnpbp4_message_map()?; - let min_depth = u5::with( - output - .lnpbp4_min_tree_depth() - .unwrap_or(PSBT_OUT_LNPBP4_MIN_TREE_DEPTH), - ); - let source = mpc::MultiSource { - min_depth, - messages, - }; - let merkle_tree = mpc::MerkleTree::try_commit(&source)?; - let entropy = merkle_tree.entropy(); - output.set_lnpbp4_entropy(entropy)?; - let commitment = merkle_tree.commitment_id(); - - // 2. Depending on the method modify output which is necessary to modify - // TODO: support non-empty tap trees - let proof = if method == CloseMethod::TapretFirst { - if output.tap_tree.is_some() { - return Err(DbcPsbtError::TapTreeNonEmpty); - } - let tapret_commitment = &TapretCommitment::with(commitment, 0); - let script_commitment = - ScriptBuf::from_bytes(TapScript::commit(tapret_commitment).to_vec()); - let builder = TaprootBuilder::with_capacity(1).add_leaf(0, script_commitment)?; - let tap_tree = TapTree::try_from(builder.clone()).expect("builder is complete"); - let internal_pk = output.tap_internal_key.ok_or(DbcPsbtError::NoInternalKey)?; - let tapret_proof = TapretProof { - path_proof: TapretPathProof::root(tapret_commitment.nonce), - internal_pk: internal_pk.into(), - }; - output.tap_tree = Some(tap_tree); - let spent_info = builder - .finalize(SECP256K1, internal_pk) - .expect("complete tree"); - let merkle_root = spent_info.merkle_root().expect("script tree present"); - - output.set_tapret_commitment(commitment, &tapret_proof.path_proof)?; - txout.script_pubkey = ScriptBuf::new_v1_p2tr(SECP256K1, internal_pk, Some(merkle_root)); - Proof::TapretFirst(tapret_proof) - } else if method == CloseMethod::OpretFirst { - output.set_opret_commitment(commitment)?; - txout.script_pubkey = ScriptBuf::new_op_return(&commitment.to_raw_array()); - Proof::OpretFirst - } else { - return Err(DbcPsbtError::MethodUnsupported(method)); - }; - - let anchor = Anchor { - txid: self.unsigned_tx.txid().to_byte_array().into(), - mpc_proof: mpc::MerkleBlock::from(merkle_tree), - dbc_proof: proof, - }; - - Ok(anchor) - } -} diff --git a/src/psbt/lnpbp4.rs b/src/psbt/lnpbp4.rs deleted file mode 100644 index 0435c315..00000000 --- a/src/psbt/lnpbp4.rs +++ /dev/null @@ -1,241 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// 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::collections::BTreeMap; - -use amplify::confinement; -use amplify::confinement::Confined; -use bitcoin::psbt::raw::ProprietaryKey; -use bitcoin::psbt::Output; -use commit_verify::mpc::{self, Message, ProtocolId}; - -/// PSBT proprietary key prefix used for LNPBP4 commitment-related data. -pub const PSBT_LNPBP4_PREFIX: &[u8] = b"LNPBP4"; - -/// Proprietary key subtype for storing LNPBP4 single commitment message under -/// some protocol in global map. -pub const PSBT_OUT_LNPBP4_MESSAGE: u8 = 0x00; -/// Proprietary key subtype for storing LNPBP4 entropy constant. -pub const PSBT_OUT_LNPBP4_ENTROPY: u8 = 0x01; -/// Proprietary key subtype for storing LNPBP4 requirement for a minimal tree -/// size. -pub const PSBT_OUT_LNPBP4_MIN_TREE_DEPTH: u8 = 0x04; - -/// Extension trait for static functions returning LNPBP4-related proprietary -/// keys. -pub trait ProprietaryKeyLnpbp4 { - fn lnpbp4_message(protocol_id: ProtocolId) -> ProprietaryKey; - fn lnpbp4_entropy() -> ProprietaryKey; - fn lnpbp4_min_tree_depth() -> ProprietaryKey; -} - -impl ProprietaryKeyLnpbp4 for ProprietaryKey { - /// Constructs [`PSBT_OUT_LNPBP4_MESSAGE`] proprietary key. - fn lnpbp4_message(protocol_id: ProtocolId) -> ProprietaryKey { - ProprietaryKey { - prefix: PSBT_LNPBP4_PREFIX.to_vec(), - subtype: PSBT_OUT_LNPBP4_MESSAGE, - key: protocol_id.to_vec(), - } - } - - /// Constructs [`PSBT_OUT_LNPBP4_ENTROPY`] proprietary key. - fn lnpbp4_entropy() -> ProprietaryKey { - ProprietaryKey { - prefix: PSBT_LNPBP4_PREFIX.to_vec(), - subtype: PSBT_OUT_LNPBP4_ENTROPY, - key: empty!(), - } - } - - /// Constructs [`PSBT_OUT_LNPBP4_MIN_TREE_DEPTH`] proprietary key. - fn lnpbp4_min_tree_depth() -> ProprietaryKey { - ProprietaryKey { - prefix: PSBT_LNPBP4_PREFIX.to_vec(), - subtype: PSBT_OUT_LNPBP4_MIN_TREE_DEPTH, - key: empty!(), - } - } -} - -/// Errors processing LNPBP4-related proprietary PSBT keys and their values. -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum Lnpbp4PsbtError { - /// the key contains invalid value. - #[from(bitcoin::hashes::Error)] - InvalidKeyValue, - - /// message map produced from PSBT inputs exceeds maximum size bounds. - #[from] - MessageMapTooLarge(confinement::Error), - - /// the key is already present, but has a different value. - AlreadySet, -} - -pub trait OutputLnpbp4 { - fn lnpbp4_message_map(&self) -> Result; - fn lnpbp4_message(&self, protocol_id: ProtocolId) -> Option; - fn lnpbp4_entropy(&self) -> Option; - fn lnpbp4_min_tree_depth(&self) -> Option; - fn set_lnpbp4_message( - &mut self, - protocol_id: ProtocolId, - message: Message, - ) -> Result; - fn set_lnpbp4_entropy(&mut self, entropy: u64) -> Result; - fn set_lnpbp4_min_tree_depth(&mut self, min_depth: u8) -> Option; -} - -/// Extension trait for [`Output`] for working with proprietary LNPBP4 -/// keys. -impl OutputLnpbp4 for Output { - /// Returns [`lnpbp4::MessageMap`] constructed from the proprietary key - /// data. - fn lnpbp4_message_map(&self) -> Result { - let map = self - .proprietary - .iter() - .filter(|(key, _)| { - // TODO: Error when only a single key is present - key.prefix == PSBT_LNPBP4_PREFIX && key.subtype == PSBT_OUT_LNPBP4_MESSAGE - }) - .map(|(key, val)| { - Ok(( - ProtocolId::from_slice(&key.key).ok_or(Lnpbp4PsbtError::InvalidKeyValue)?, - Message::from_slice(val).ok_or(Lnpbp4PsbtError::InvalidKeyValue)?, - )) - }) - .collect::, Lnpbp4PsbtError>>()?; - Confined::try_from(map).map_err(Lnpbp4PsbtError::from) - } - - /// Returns a valid LNPBP-4 [`Message`] associated with the given - /// [`ProtocolId`], if any. - /// - /// We do not error on invalid data in order to support future update of - /// this proprietary key to a standard one. In this case, the invalid - /// data will be filtered at the moment of PSBT deserialization and this - /// function will return `None` only in situations when the key is absent. - fn lnpbp4_message(&self, protocol_id: ProtocolId) -> Option { - let key = ProprietaryKey::lnpbp4_message(protocol_id); - let data = self.proprietary.get(&key)?; - Message::from_slice(data) - } - - /// Returns a valid LNPBP-4 entropy value, if present. - /// - /// We do not error on invalid data in order to support future update of - /// this proprietary key to a standard one. In this case, the invalid - /// data will be filtered at the moment of PSBT deserialization and this - /// function will return `None` only in situations when the key is absent. - fn lnpbp4_entropy(&self) -> Option { - let key = ProprietaryKey::lnpbp4_entropy(); - let data = self.proprietary.get(&key)?; - if data.len() != 8 { - return None; - } - let mut buf = [0u8; 8]; - buf.copy_from_slice(data); - Some(u64::from_le_bytes(buf)) - } - - /// Returns a valid LNPBP-4 minimal tree depth value, if present. - /// - /// # Errors - /// - /// If the key is present, but it's value can't be deserialized as a valid - /// minimal tree depth value. - fn lnpbp4_min_tree_depth(&self) -> Option { - let key = ProprietaryKey::lnpbp4_min_tree_depth(); - let data = self.proprietary.get(&key)?; - if data.len() != 1 { - return None; - } - Some(data[0]) - } - - /// Sets LNPBP4 [`Message`] for the given [`ProtocolId`]. - /// - /// # Returns - /// - /// `true`, if the message was set successfully, `false` if this message was - /// already present for this protocol. - /// - /// # Errors - /// - /// If the key for the given [`ProtocolId`] is already present and the - /// message is different. - fn set_lnpbp4_message( - &mut self, - protocol_id: ProtocolId, - message: Message, - ) -> Result { - let key = ProprietaryKey::lnpbp4_message(protocol_id); - let val = message.to_vec(); - if let Some(v) = self.proprietary.get(&key) { - if v != &val { - return Err(Lnpbp4PsbtError::InvalidKeyValue); - } - return Ok(false); - } - self.proprietary.insert(key, val); - Ok(true) - } - - /// Sets LNPBP4 entropy value. - /// - /// # Returns - /// - /// `true`, if the entropy was set successfully, `false` if this entropy - /// value was already set. - /// - /// # Errors - /// - /// If the entropy was already set with a different value than the provided - /// one. - fn set_lnpbp4_entropy(&mut self, entropy: u64) -> Result { - let key = ProprietaryKey::lnpbp4_entropy(); - let val = entropy.to_le_bytes().to_vec(); - if let Some(v) = self.proprietary.get(&key) { - if v != &val { - return Err(Lnpbp4PsbtError::InvalidKeyValue); - } - return Ok(false); - } - self.proprietary.insert(key, val); - Ok(true) - } - - /// Sets LNPBP4 min tree depth value. - /// - /// # Returns - /// - /// Previous minimal tree depth value, if it was present and valid - or None - /// if the value was absent or invalid (the new value is still assigned). - fn set_lnpbp4_min_tree_depth(&mut self, min_depth: u8) -> Option { - let key = ProprietaryKey::lnpbp4_min_tree_depth(); - let val = vec![min_depth]; - let prev = self.lnpbp4_min_tree_depth(); - self.proprietary.insert(key, val).and(prev) - } -} diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs deleted file mode 100644 index 168945d3..00000000 --- a/src/psbt/mod.rs +++ /dev/null @@ -1,54 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// 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. - -//! Managing RGB-related proprietary keys inside PSBT. -//! -//! Supports Tapret, Opret, P2C and S2C commitments and LNPBP4 structures used -//! by all of them. - -// TODO: Move to BP wallet -mod lnpbp4; -// TODO: Move to BP wallet -mod dbc; -// TODO: Move to BP wallet -pub mod opret; -// TODO: Move to BP wallet -pub mod tapret; -mod rgb; - -pub use dbc::{DbcPsbtError, PsbtDbc}; -pub use lnpbp4::{ - Lnpbp4PsbtError, ProprietaryKeyLnpbp4, PSBT_LNPBP4_PREFIX, PSBT_OUT_LNPBP4_ENTROPY, - PSBT_OUT_LNPBP4_MESSAGE, PSBT_OUT_LNPBP4_MIN_TREE_DEPTH, -}; -pub use opret::{ - OpretKeyError, ProprietaryKeyOpret, PSBT_OPRET_PREFIX, PSBT_OUT_OPRET_COMMITMENT, - PSBT_OUT_OPRET_HOST, -}; -pub use tapret::{ - ProprietaryKeyTapret, TapretKeyError, PSBT_IN_TAPRET_TWEAK, PSBT_OUT_TAPRET_COMMITMENT, - PSBT_OUT_TAPRET_HOST, PSBT_OUT_TAPRET_PROOF, PSBT_TAPRET_PREFIX, -}; - -pub use self::rgb::{ - ProprietaryKeyRgb, RgbExt, RgbInExt, RgbOutExt, RgbPsbtError, PSBT_GLOBAL_RGB_TRANSITION, - PSBT_IN_RGB_CONSUMED_BY, PSBT_OUT_RGB_VELOCITY_HINT, PSBT_RGB_PREFIX, -}; diff --git a/src/psbt/opret.rs b/src/psbt/opret.rs deleted file mode 100644 index 2902d97c..00000000 --- a/src/psbt/opret.rs +++ /dev/null @@ -1,194 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// 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. - -//! Processing proprietary PSBT keys related to OP_RETURN (or opret) -//! commitments. -//! -//! NB: Wallets supporting opret commitments must do that through the use of -//! deterministic bitcoin commitments crate (`bp-dpc`) in order to ensure -//! that multiple protocols can put commitment inside the same transaction -//! without collisions between them. -//! -//! This module provides support for marking PSBT outputs which may host -//! opret commitment and populating PSBT with the data related to opret -//! commitments. - -use bitcoin::psbt::raw::ProprietaryKey; -use bitcoin::psbt::Output; -use commit_verify::mpc; - -/// PSBT proprietary key prefix used for opret commitment. -pub const PSBT_OPRET_PREFIX: &[u8] = b"OPRET"; - -/// Proprietary key subtype marking PSBT outputs which may host opret -/// commitment. -pub const PSBT_OUT_OPRET_HOST: u8 = 0x00; -/// Proprietary key subtype holding 32-byte commitment which will be put into -/// opret data. -pub const PSBT_OUT_OPRET_COMMITMENT: u8 = 0x01; - -/// Extension trait for static functions returning opret-related proprietary -/// keys. -pub trait ProprietaryKeyOpret { - /// Constructs [`PSBT_OUT_OPRET_HOST`] proprietary key. - fn opret_host() -> ProprietaryKey { - ProprietaryKey { - prefix: PSBT_OPRET_PREFIX.to_vec(), - subtype: PSBT_OUT_OPRET_HOST, - key: vec![], - } - } - - /// Constructs [`PSBT_OUT_OPRET_COMMITMENT`] proprietary key. - fn opret_commitment() -> ProprietaryKey { - ProprietaryKey { - prefix: PSBT_OPRET_PREFIX.to_vec(), - subtype: PSBT_OUT_OPRET_COMMITMENT, - key: vec![], - } - } -} - -impl ProprietaryKeyOpret for ProprietaryKey {} - -/// Errors processing opret-related proprietary PSBT keys and their values. -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Error)] -#[display(doc_comments)] -pub enum OpretKeyError { - /// output already contains commitment; there must be a single commitment - /// per output. - OutputAlreadyHasCommitment, - - /// the output can't host a commitment since it does not contain OP_RETURN - /// script - NonOpReturnOutput, - - /// the output is not marked to host opret commitments. Please first set - /// PSBT_OUT_OPRET_HOST flag. - OpretProhibited, -} - -pub trait OutputOpret { - fn is_opret_host(&self) -> bool; - fn set_opret_host(&mut self) -> Result; - fn has_opret_commitment(&self) -> Result; - fn opret_commitment(&self) -> Option; - fn set_opret_commitment(&mut self, commitment: mpc::Commitment) -> Result<(), OpretKeyError>; -} - -impl OutputOpret for Output { - /// Returns whether this output may contain opret commitment. This is - /// detected by the presence of [`PSBT_OUT_OPRET_HOST`] key. - #[inline] - fn is_opret_host(&self) -> bool { - // TODO: Check that output is OP_RETURN - self.proprietary.contains_key(&ProprietaryKey::opret_host()) // && self.script.is_op_return() - } - - /// Allows opret commitments for this output. Returns whether opret - /// commitments were enabled before. - /// - /// # Errors - /// - /// If output script is not OP_RETURN script - #[inline] - fn set_opret_host(&mut self) -> Result { - // TODO: Check that output is OP_RETURN - /* if !self.script.is_op_return() { - return Err(OpretKeyError::NonOpReturnOutput); - } */ - Ok(self - .proprietary - .insert(ProprietaryKey::opret_host(), vec![]) - .is_some()) - } - - /// Detects presence of a valid [`PSBT_OUT_OPRET_COMMITMENT`]. - /// - /// If [`PSBT_OUT_OPRET_COMMITMENT`] is absent or its value is invalid, - /// returns `false`. In the future, when `PSBT_OUT_OPRET_COMMITMENT` will - /// become a standard and non-custom key, PSBTs with invalid key values - /// will error at deserialization and this function will return `false` - /// only in cases when the output does not have - /// `PSBT_OUT_OPRET_COMMITMENT`. - /// - /// # Errors - /// - /// If output script is not OP_RETURN script - fn has_opret_commitment(&self) -> Result { - // TODO: Check that output is OP_RETURN - /* - if !self.script.is_op_return() { - return Err(OpretKeyError::NonOpReturnOutput); - }*/ - Ok(self - .proprietary - .contains_key(&ProprietaryKey::opret_commitment())) - } - - /// Returns valid opret commitment from the [`PSBT_OUT_OPRET_COMMITMENT`] - /// key, if present. If the commitment is absent or invalid, returns - /// `None`. - /// - /// We do not error on invalid commitments in order to support future update - /// of this proprietary key to the standard one. In this case, the - /// invalid commitments (having non-32 bytes) will be filtered at the - /// moment of PSBT deserialization and this function will return `None` - /// only in situations when the commitment is absent. - /// - /// # Errors - /// - /// If output script is not OP_RETURN script - fn opret_commitment(&self) -> Option { - // TODO: Check that output is OP_RETURN - /*if !self.script.is_op_return() { - return Err(OpretKeyError::NonOpReturnOutput); - }*/ - let data = self.proprietary.get(&ProprietaryKey::opret_commitment())?; - mpc::Commitment::from_slice(data) - } - - /// Assigns value of the opreturn commitment to this PSBT output, by - /// adding [`PSBT_OUT_OPRET_COMMITMENT`] proprietary key containing the - /// 32-byte commitment as its value. - /// - /// Errors with [`OpretKeyError::OutputAlreadyHasCommitment`] if the - /// commitment is already present in the output. - /// - /// # Errors - /// - /// If output script is not OP_RETURN script or opret commitments are not - /// enabled for this output. - fn set_opret_commitment(&mut self, commitment: mpc::Commitment) -> Result<(), OpretKeyError> { - if !self.is_opret_host() { - return Err(OpretKeyError::OpretProhibited); - } - - if self.has_opret_commitment()? { - return Err(OpretKeyError::OutputAlreadyHasCommitment); - } - - self.proprietary - .insert(ProprietaryKey::opret_commitment(), commitment.to_vec()); - - Ok(()) - } -} diff --git a/src/psbt/tapret.rs b/src/psbt/tapret.rs deleted file mode 100644 index 17917185..00000000 --- a/src/psbt/tapret.rs +++ /dev/null @@ -1,246 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// 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. - -//! Processing proprietary PSBT keys related to taproot-based OP_RETURN -//! (or tapret) commitments. -//! -//! NB: Wallets supporting tapret commitments must do that through the use of -//! deterministic bitcoin commitments crate (`bp-dpc`) in order to ensure -//! that multiple protocols can put commitment inside the same transaction -//! without collisions between them. -//! -//! This module provides support for marking PSBT outputs which may host -//! tapreturn commitment and populating PSBT with the data related to tapret -//! commitments. - -use amplify::confinement::{Confined, U16}; -use bitcoin::psbt::raw::ProprietaryKey; -use bitcoin::psbt::Output; -use bp::dbc::tapret::TapretPathProof; -use commit_verify::mpc; -use strict_encoding::{StrictDeserialize, StrictSerialize}; - -/// PSBT proprietary key prefix used for tapreturn commitment. -pub const PSBT_TAPRET_PREFIX: &[u8] = b"TAPRET"; - -/// Proprietary key subtype for PSBT inputs containing the applied tapret tweak -/// information. -pub const PSBT_IN_TAPRET_TWEAK: u8 = 0x00; - -/// Proprietary key subtype marking PSBT outputs which may host tapreturn -/// commitment. -pub const PSBT_OUT_TAPRET_HOST: u8 = 0x00; -/// Proprietary key subtype holding 32-byte commitment which will be put into -/// tapreturn tweak. -pub const PSBT_OUT_TAPRET_COMMITMENT: u8 = 0x01; -/// Proprietary key subtype holding merkle branch path to tapreturn tweak inside -/// the taptree structure. -pub const PSBT_OUT_TAPRET_PROOF: u8 = 0x02; - -/// Extension trait for static functions returning tapreturn-related proprietary -/// keys. -pub trait ProprietaryKeyTapret { - /// Constructs [`PSBT_IN_TAPRET_TWEAK`] proprietary key. - fn tapret_tweak() -> ProprietaryKey { - ProprietaryKey { - prefix: PSBT_TAPRET_PREFIX.to_vec(), - subtype: PSBT_IN_TAPRET_TWEAK, - key: vec![], - } - } - - /// Constructs [`PSBT_OUT_TAPRET_HOST`] proprietary key. - fn tapret_host() -> ProprietaryKey { - ProprietaryKey { - prefix: PSBT_TAPRET_PREFIX.to_vec(), - subtype: PSBT_OUT_TAPRET_HOST, - key: vec![], - } - } - - /// Constructs [`PSBT_OUT_TAPRET_COMMITMENT`] proprietary key. - fn tapret_commitment() -> ProprietaryKey { - ProprietaryKey { - prefix: PSBT_TAPRET_PREFIX.to_vec(), - subtype: PSBT_OUT_TAPRET_COMMITMENT, - key: vec![], - } - } - - /// Constructs [`PSBT_OUT_TAPRET_PROOF`] proprietary key. - fn tapret_proof() -> ProprietaryKey { - ProprietaryKey { - prefix: PSBT_TAPRET_PREFIX.to_vec(), - subtype: PSBT_OUT_TAPRET_PROOF, - key: vec![], - } - } -} - -impl ProprietaryKeyTapret for ProprietaryKey {} - -/// Errors processing tapret-related proprietary PSBT keys and their values. -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum TapretKeyError { - /// output already contains commitment; there must be a single commitment - /// per output. - OutputAlreadyHasCommitment, - - /// the output is not marked to host tapret commitments. Please first set - /// PSBT_OUT_TAPRET_HOST flag. - TapretProhibited, - - /// the provided tapret proof is invalid: it has a script longer than 64KiB. - InvalidProof, - - /// the provided output is not a taproot output and can't host a tapret - /// commitment. - NotTaprootOutput, -} - -pub trait OutputTapret { - fn is_tapret_host(&self) -> bool; - fn set_tapret_host(&mut self) -> Result<(), TapretKeyError>; - fn has_tapret_commitment(&self) -> bool; - fn tapret_commitment(&self) -> Option; - fn set_tapret_commitment( - &mut self, - commitment: mpc::Commitment, - proof: &TapretPathProof, - ) -> Result<(), TapretKeyError>; - fn has_tapret_proof(&self) -> bool; - fn tapret_proof(&self) -> Option; -} - -impl OutputTapret for Output { - /// Returns whether this output may contain tapret commitment. This is - /// detected by the presence of [`PSBT_OUT_TAPRET_HOST`] key. - #[inline] - fn is_tapret_host(&self) -> bool { - self.proprietary - .contains_key(&ProprietaryKey::tapret_host()) - } - - /// Sets [`PSBT_OUT_TAPRET_HOST`] key. - /// - /// # Errors - /// - /// Errors with [`TapretKeyError::NotTaprootOutput`] if the output is not a - /// taproot output. - fn set_tapret_host(&mut self) -> Result<(), TapretKeyError> { - // TODO: With new PSBT library check scriptPubkey directly - if self.tap_internal_key.is_none() { - return Err(TapretKeyError::NotTaprootOutput); - } - - self.proprietary - .insert(ProprietaryKey::tapret_host(), vec![]); - - Ok(()) - } - - /// Detects presence of a valid [`PSBT_OUT_TAPRET_COMMITMENT`]. - /// - /// If [`PSBT_OUT_TAPRET_COMMITMENT`] is absent or its value is invalid, - /// returns `false`. In the future, when `PSBT_OUT_TAPRET_COMMITMENT` will - /// become a standard and non-custom key, PSBTs with invalid key values - /// will error at deserialization and this function will return `false` - /// only in cases when the output does not have - /// `PSBT_OUT_TAPRET_COMMITMENT`. - fn has_tapret_commitment(&self) -> bool { self.tapret_commitment().is_some() } - - /// Returns valid tapret commitment from the [`PSBT_OUT_TAPRET_COMMITMENT`] - /// key, if present. If the commitment is absent or invalid, returns - /// `None`. - /// - /// We do not error on invalid commitments in order to support future update - /// of this proprietary key to the standard one. In this case, the - /// invalid commitments (having non-32 bytes) will be filtered at the - /// moment of PSBT deserialization and this function will return `None` - /// only in situations when the commitment is absent. - fn tapret_commitment(&self) -> Option { - let data = self.proprietary.get(&ProprietaryKey::tapret_commitment())?; - mpc::Commitment::from_slice(data) - } - - /// Assigns value of the tapreturn commitment to this PSBT output, by - /// adding [`PSBT_OUT_TAPRET_COMMITMENT`] and [`PSBT_OUT_TAPRET_PROOF`] - /// proprietary keys containing the 32-byte commitment as its proof. - /// - /// # Errors - /// - /// Errors with [`TapretKeyError::OutputAlreadyHasCommitment`] if the - /// commitment is already present in the output, and with - /// [`TapretKeyError::TapretProhibited`] if tapret commitments are not - /// enabled for this output. - fn set_tapret_commitment( - &mut self, - commitment: mpc::Commitment, - proof: &TapretPathProof, - ) -> Result<(), TapretKeyError> { - if !self.is_tapret_host() { - return Err(TapretKeyError::TapretProhibited); - } - - if self.has_tapret_commitment() { - return Err(TapretKeyError::OutputAlreadyHasCommitment); - } - - self.proprietary - .insert(ProprietaryKey::tapret_commitment(), commitment.to_vec()); - - let val = proof - .to_strict_serialized::() - .map_err(|_| TapretKeyError::InvalidProof)?; - self.proprietary - .insert(ProprietaryKey::tapret_proof(), val.into_inner()); - - Ok(()) - } - - /// Detects presence of a valid [`PSBT_OUT_TAPRET_PROOF`]. - /// - /// If [`PSBT_OUT_TAPRET_PROOF`] is absent or its value is invalid, - /// returns `false`. In the future, when `PSBT_OUT_TAPRET_PROOF` will - /// become a standard and non-custom key, PSBTs with invalid key values - /// will error at deserialization and this function will return `false` - /// only in cases when the output does not have `PSBT_OUT_TAPRET_PROOF`. - fn has_tapret_proof(&self) -> bool { self.tapret_proof().is_some() } - - /// Returns valid tapret commitment proof from the [`PSBT_OUT_TAPRET_PROOF`] - /// key, if present. If the commitment is absent or invalid, returns `None`. - /// - /// We do not error on invalid proofs in order to support future update of - /// this proprietary key to a standard one. In this case, the invalid - /// commitments (having non-32 bytes) will be filtered at the moment of PSBT - /// deserialization and this function will return `None` only in situations - /// when the commitment is absent. - /// - /// Function returns generic type since the real type will create dependency - /// on `bp-dpc` crate, which will result in circular dependency with the - /// current crate. - fn tapret_proof(&self) -> Option { - let data = self.proprietary.get(&ProprietaryKey::tapret_proof())?; - let vec = Confined::try_from_iter(data.iter().copied()).ok()?; - TapretPathProof::from_strict_serialized::(vec).ok() - } -} diff --git a/std/Cargo.toml b/std/Cargo.toml index 17b40211..2eb4f43f 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rgb-std" -version = "0.10.7" +version = "0.11.0-alpha" description = "RGB standard library for working with smart contracts on Bitcoin & Lightning" keywords = ["bitcoin", "lightning", "rgb", "smart-contracts", "lnp-bp"] categories = ["cryptography::cryptocurrencies"] @@ -13,33 +13,41 @@ rust-version = { workspace = true } readme = "../README.md" [lib] -name = "rgbstd" +name = "rgb" crate-type = ["cdylib", "rlib"] # We need this for WASM -[[bin]] -name = "rgb-stl" - [dependencies] amplify = { workspace = true } strict_encoding = { workspace = true } strict_types = { workspace = true } commit_verify = { workspace = true } bp-core = { workspace = true } +bp-std = { workspace = true, optional = true } +descriptors = "=0.10.0-BP-beta.1" rgb-core = { workspace = true } baid58 = { workspace = true } base85 = "=2.0.0" -chrono = "0.4.26" -serde_crate = { package = "serde", version = "1", features = ["derive"] } +chrono = "0.4.31" +serde_crate = { workspace = true, optional = true } +serde_with = { workspace = true, optional = true } +cfg_eval = { workspace = true, optional = true } +indexmap = "2.0.2" [features] -default = [] -all = ["fs", "serde"] +default = ["descriptor"] +all = ["fs", "descriptor", "serde"] +descriptor = ["bp-std"] serde = [ + "serde_crate", + "serde_with", + "cfg_eval", "amplify/serde", - "strict_encoding/serde", "strict_types/serde", + "strict_encoding/serde", + "strict_types/serde", "commit_verify/serde", "bp-core/serde", "rgb-core/serde", + "bp-std/serde", ] fs = [] diff --git a/std/src/containers/bindle.rs b/std/src/containers/bindle.rs index b1a82643..47f12a6a 100644 --- a/std/src/containers/bindle.rs +++ b/std/src/containers/bindle.rs @@ -25,6 +25,7 @@ use std::collections::BTreeMap; use std::fmt::{Debug, Display}; +use std::io::Read; use std::ops::Deref; use std::str::FromStr; @@ -33,9 +34,10 @@ pub use _fs::*; use amplify::confinement; use amplify::confinement::{Confined, TinyVec, U24}; use baid58::Baid58ParseError; -use rgb::{BundleId, ContractId, Schema, SchemaId, SchemaRoot}; +use rgb::{BundleId, ContractId, Schema, SchemaId, SchemaRoot, SubSchema}; use strict_encoding::{ - StrictDecode, StrictDeserialize, StrictDumb, StrictEncode, StrictSerialize, StrictType, + StrictDecode, StrictDeserialize, StrictDumb, StrictEncode, StrictReader, StrictSerialize, + StrictType, }; use crate::containers::transfer::TransferId; @@ -277,14 +279,49 @@ impl Display for Bindle { } } +impl Bindle { + pub fn load(mut data: impl Read) -> Result { + let mut rgb = [0u8; 3]; + let mut magic = [0u8; 4]; + data.read_exact(&mut rgb)?; + data.read_exact(&mut magic)?; + if rgb != *b"RGB" || magic != C::MAGIC { + return Err(LoadError::InvalidMagic); + } + let mut reader = StrictReader::with(usize::MAX, data); + let me = Self::strict_decode(&mut reader)?; + Ok(me) + } +} + +impl UniversalBindle { + pub fn load(mut data: impl Read) -> Result { + let mut rgb = [0u8; 3]; + let mut magic = [0u8; 4]; + data.read_exact(&mut rgb)?; + data.read_exact(&mut magic)?; + if rgb != *b"RGB" { + return Err(LoadError::InvalidMagic); + } + let mut reader = StrictReader::with(usize::MAX, data); + Ok(match magic { + x if x == Iface::MAGIC => Bindle::::strict_decode(&mut reader)?.into(), + x if x == SubSchema::MAGIC => Bindle::::strict_decode(&mut reader)?.into(), + x if x == IfaceImpl::MAGIC => Bindle::::strict_decode(&mut reader)?.into(), + x if x == Contract::MAGIC => Bindle::::strict_decode(&mut reader)?.into(), + x if x == Transfer::MAGIC => Bindle::::strict_decode(&mut reader)?.into(), + _ => return Err(LoadError::InvalidMagic), + }) + } +} + #[cfg(feature = "fs")] mod _fs { - use std::io::{Read, Write}; + use std::io::Write; use std::path::Path; use std::{fs, io}; - use rgb::SubSchema; - use strict_encoding::{DecodeError, StrictEncode, StrictReader, StrictWriter}; + use strict_encoding::{DecodeError, StrictEncode, StrictWriter}; use super::*; @@ -326,18 +363,9 @@ mod _fs { } impl Bindle { - pub fn load(path: impl AsRef) -> Result { - let mut rgb = [0u8; 3]; - let mut magic = [0u8; 4]; - let mut file = fs::File::open(path)?; - file.read_exact(&mut rgb)?; - file.read_exact(&mut magic)?; - if rgb != *b"RGB" || magic != C::MAGIC { - return Err(LoadError::InvalidMagic); - } - let mut reader = StrictReader::with(usize::MAX, file); - let me = Self::strict_decode(&mut reader)?; - Ok(me) + pub fn load_file(path: impl AsRef) -> Result { + let file = fs::File::open(path)?; + Self::load(file) } pub fn save(&self, path: impl AsRef) -> Result<(), io::Error> { @@ -351,28 +379,9 @@ mod _fs { } impl UniversalBindle { - pub fn load(path: impl AsRef) -> Result { - let mut rgb = [0u8; 3]; - let mut magic = [0u8; 4]; - let mut file = fs::File::open(path)?; - file.read_exact(&mut rgb)?; - file.read_exact(&mut magic)?; - if rgb != *b"RGB" { - return Err(LoadError::InvalidMagic); - } - let mut reader = StrictReader::with(usize::MAX, file); - Ok(match magic { - x if x == Iface::MAGIC => Bindle::::strict_decode(&mut reader)?.into(), - x if x == SubSchema::MAGIC => { - Bindle::::strict_decode(&mut reader)?.into() - } - x if x == IfaceImpl::MAGIC => { - Bindle::::strict_decode(&mut reader)?.into() - } - x if x == Contract::MAGIC => Bindle::::strict_decode(&mut reader)?.into(), - x if x == Transfer::MAGIC => Bindle::::strict_decode(&mut reader)?.into(), - _ => return Err(LoadError::InvalidMagic), - }) + pub fn load_file(path: impl AsRef) -> Result { + let file = fs::File::open(path)?; + Self::load(file) } } } diff --git a/std/src/descriptor.rs b/std/src/descriptor.rs new file mode 100644 index 00000000..6de9b793 --- /dev/null +++ b/std/src/descriptor.rs @@ -0,0 +1,209 @@ +// 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::collections::BTreeMap; +use std::ops::Range; +use std::str::FromStr; +use std::{iter, vec}; + +use bp::dbc::tapret::TapretCommitment; +use bpstd::{ + CompressedPk, Derive, DeriveCompr, DeriveSet, DeriveXOnly, DerivedScript, Idx, IndexError, + IndexParseError, KeyOrigin, NormalIndex, TapDerivation, Terminal, XOnlyPk, XpubDerivable, + XpubSpec, +}; +use descriptors::{Descriptor, DescriptorStd, TrKey}; +use indexmap::IndexMap; +#[cfg(feature = "serde")] +use serde_with::DisplayFromStr; + +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +#[repr(u8)] +pub enum RgbKeychain { + #[display("0", alt = "0")] + External = 0, + + #[display("1", alt = "1")] + Internal = 1, + + #[display("9", alt = "9")] + Rgb = 9, + + #[display("10", alt = "10")] + Tapret = 10, +} + +impl RgbKeychain { + pub fn is_seal(self) -> bool { self == Self::Rgb || self == Self::Tapret } +} + +impl FromStr for RgbKeychain { + type Err = IndexParseError; + + fn from_str(s: &str) -> Result { + match NormalIndex::from_str(s)? { + NormalIndex::ZERO => Ok(RgbKeychain::External), + NormalIndex::ONE => Ok(RgbKeychain::Internal), + val => Err(IndexError { + what: "non-standard keychain", + invalid: val.index(), + start: 0, + end: 1, + } + .into()), + } + } +} + +#[cfg_attr( + feature = "serde", + cfg_eval, + serde_as, + derive(Serialize, Deserialize), + serde( + crate = "serde_crate", + bound( + serialize = "K: std::fmt::Display", + deserialize = "K: std::str::FromStr, K::Err: std::fmt::Display" + ) + ) +)] +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +pub struct TapretKey { + #[cfg_attr(feature = "serde", serde_as(as = "DisplayFromStr"))] + pub internal_key: K, + #[cfg_attr(feature = "serde", serde_as(as = "BTreeMap<_, DisplayFromStr>"))] + pub tweaks: BTreeMap, +} + +impl TapretKey { + pub fn new_unfunded(internal_key: K) -> Self { + TapretKey { + internal_key, + tweaks: empty!(), + } + } +} + +impl Derive for TapretKey { + fn keychains(&self) -> Range { + 0..2 /* FIXME */ + } + + fn derive(&self, change: u8, index: impl Into) -> DerivedScript { + // TODO: Apply tweaks + let internal_key = self.internal_key.derive(change, index); + DerivedScript::TaprootKeyOnly(internal_key.into()) + } +} + +impl From for TapretKey { + fn from(tr: K) -> Self { + TapretKey { + internal_key: tr, + tweaks: none!(), + } + } +} + +impl From> for TapretKey { + fn from(tr: TrKey) -> Self { + TapretKey { + internal_key: tr.into_internal_key(), + tweaks: none!(), + } + } +} + +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde( + crate = "serde_crate", + rename_all = "camelCase", + bound( + serialize = "S::XOnly: std::fmt::Display", + deserialize = "S::XOnly: std::str::FromStr, ::Err: \ + std::fmt::Display" + ) + ) +)] +#[derive(Clone, Eq, PartialEq, Hash, Debug, From)] +pub enum DescriptorRgb { + None, + + #[from] + TapretKey(TapretKey), +} + +impl Default for DescriptorRgb { + fn default() -> Self { DescriptorRgb::None } +} + +impl Derive for DescriptorRgb { + fn keychains(&self) -> Range { + match self { + DescriptorRgb::None => Range::default(), + DescriptorRgb::TapretKey(d) => d.keychains(), + } + } + + fn derive(&self, change: u8, index: impl Into) -> DerivedScript { + match self { + DescriptorRgb::None => todo!(), + DescriptorRgb::TapretKey(d) => d.derive(change, index), + } + } +} + +impl + DeriveCompr + DeriveXOnly> Descriptor + for DescriptorRgb +where Self: Derive +{ + type KeyIter<'k> = vec::IntoIter<&'k K> where Self: 'k, K: 'k; + type VarIter<'v> = iter::Empty<&'v ()> where Self: 'v, (): 'v; + type XpubIter<'x> = vec::IntoIter<&'x XpubSpec> where Self: 'x; + + fn keys(&self) -> Self::KeyIter<'_> { todo!() } + + fn vars(&self) -> Self::VarIter<'_> { todo!() } + + fn xpubs(&self) -> Self::XpubIter<'_> { todo!() } + + fn compr_keyset(&self, terminal: Terminal) -> IndexMap { todo!() } + + fn xonly_keyset(&self, terminal: Terminal) -> IndexMap { todo!() } +} + +impl From for DescriptorRgb { + fn from(descr: DescriptorStd) -> Self { + match descr { + DescriptorStd::Wpkh(_) => todo!(), + DescriptorStd::TrKey(tr) => DescriptorRgb::TapretKey(tr.into()), + _ => todo!(), + } + } +} diff --git a/std/src/interface/contract.rs b/std/src/interface/contract.rs index 50d01091..ceb6df0e 100644 --- a/std/src/interface/contract.rs +++ b/std/src/interface/contract.rs @@ -20,6 +20,7 @@ // limitations under the License. use std::collections::{BTreeSet, HashSet}; +use std::ops::Deref; use amplify::confinement::{LargeOrdMap, LargeVec, SmallVec}; use bp::Outpoint; @@ -31,7 +32,7 @@ use strict_encoding::FieldName; use strict_types::typify::TypedVal; use strict_types::{decode, StrictVal}; -use crate::interface::IfaceImpl; +use crate::interface::{IfaceId, IfaceImpl}; #[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] #[display(doc_comments)] @@ -44,7 +45,7 @@ pub enum ContractError { Reify(decode::Error), } -#[derive(Clone, Eq, PartialEq, Debug, Display, From)] +#[derive(Clone, Eq, PartialEq, Debug, Hash, Display, From)] #[display(inner)] pub enum TypedState { #[display("")] @@ -57,7 +58,7 @@ pub enum TypedState { Attachment(AttachedState), } -#[derive(Clone, Eq, PartialEq, Debug, Display)] +#[derive(Clone, Eq, PartialEq, Hash, Debug, Display)] #[display("{id}:{media_type}")] pub struct AttachedState { pub id: AttachId, @@ -98,13 +99,35 @@ pub trait OutpointFilter { fn include_outpoint(&self, outpoint: Outpoint) -> bool; } -impl OutpointFilter for Option<&[Outpoint]> { +pub struct FilterIncludeAll; +pub struct FilterExclude(pub T); + +impl OutpointFilter for &T { + fn include_outpoint(&self, outpoint: Outpoint) -> bool { (*self).include_outpoint(outpoint) } +} + +impl OutpointFilter for &mut T { + fn include_outpoint(&self, outpoint: Outpoint) -> bool { + self.deref().include_outpoint(outpoint) + } +} + +impl OutpointFilter for Option { fn include_outpoint(&self, outpoint: Outpoint) -> bool { - self.map(|filter| filter.include_outpoint(outpoint)) + self.as_ref() + .map(|filter| filter.include_outpoint(outpoint)) .unwrap_or(true) } } +impl OutpointFilter for FilterIncludeAll { + fn include_outpoint(&self, _: Outpoint) -> bool { true } +} + +impl OutpointFilter for FilterExclude { + fn include_outpoint(&self, outpoint: Outpoint) -> bool { !self.0.include_outpoint(outpoint) } +} + impl OutpointFilter for &[Outpoint] { fn include_outpoint(&self, outpoint: Outpoint) -> bool { self.contains(&outpoint) } } @@ -189,4 +212,11 @@ impl ContractIface { ) -> LargeOrdMap> { todo!() } + + pub fn wrap(self) -> W { W::from(self) } +} + +pub trait IfaceWrapper: From { + const IFACE_NAME: &'static str; + const IFACE_ID: IfaceId; } diff --git a/std/src/interface/iface.rs b/std/src/interface/iface.rs index 3552b6e3..66f2338b 100644 --- a/std/src/interface/iface.rs +++ b/std/src/interface/iface.rs @@ -81,6 +81,7 @@ impl FromStr for IfaceId { } } impl IfaceId { + pub const fn from_array(id: [u8; 32]) -> Self { IfaceId(Bytes32::from_array(id)) } pub fn to_mnemonic(&self) -> String { self.to_baid58().mnemonic() } } diff --git a/std/src/interface/mod.rs b/std/src/interface/mod.rs index 6dca68ab..362e9ce0 100644 --- a/std/src/interface/mod.rs +++ b/std/src/interface/mod.rs @@ -33,7 +33,10 @@ pub mod rgb25; mod suppl; pub use builder::{BuilderError, ContractBuilder, TransitionBuilder}; -pub use contract::{ContractIface, FungibleAllocation, OutpointFilter, TypedState}; +pub use contract::{ + ContractIface, FilterExclude, FilterIncludeAll, FungibleAllocation, IfaceWrapper, + OutpointFilter, TypedState, +}; pub use iface::{ ArgMap, ArgSpec, AssignIface, ExtensionIface, GenesisIface, GlobalIface, Iface, IfaceId, OwnedIface, Req, TransitionIface, ValencyIface, diff --git a/std/src/interface/rgb20.rs b/std/src/interface/rgb20.rs index 0456c7a9..49432902 100644 --- a/std/src/interface/rgb20.rs +++ b/std/src/interface/rgb20.rs @@ -26,7 +26,9 @@ use strict_types::{CompileError, LibBuilder, TypeLib}; use super::{ AssignIface, GenesisIface, GlobalIface, Iface, OwnedIface, Req, TransitionIface, VerNo, }; -use crate::interface::{ArgSpec, ContractIface, FungibleAllocation, OutpointFilter}; +use crate::interface::{ + ArgSpec, ContractIface, FungibleAllocation, IfaceId, IfaceWrapper, OutpointFilter, +}; use crate::stl::{ rgb_contract_stl, Amount, ContractData, DivisibleAssetSpec, StandardTypes, Timestamp, }; @@ -239,13 +241,22 @@ pub struct Rgb20(ContractIface); impl From for Rgb20 { fn from(iface: ContractIface) -> Self { - if iface.iface.iface_id != rgb20().iface_id() { + if iface.iface.iface_id != Rgb20::IFACE_ID { panic!("the provided interface is not RGB20 interface"); } Self(iface) } } +impl IfaceWrapper for Rgb20 { + const IFACE_NAME: &'static str = LIB_NAME_RGB20; + const IFACE_ID: IfaceId = IfaceId::from_array([ + 0x2e, 0x8c, 0x09, 0xc4, 0xbd, 0xb9, 0x5a, 0x46, 0x95, 0x4b, 0x29, 0x88, 0xac, 0x48, 0x89, + 0xa3, 0x5c, 0xb7, 0x7c, 0x90, 0x0a, 0x94, 0xf8, 0x8b, 0x1a, 0x33, 0xb5, 0x76, 0x2d, 0x43, + 0xfb, 0x3d, + ]); +} + impl Rgb20 { pub fn spec(&self) -> DivisibleAssetSpec { let strict_val = &self @@ -263,11 +274,11 @@ impl Rgb20 { Timestamp::from_strict_val_unchecked(strict_val) } - pub fn balance(&self, filter: &impl OutpointFilter) -> u64 { + pub fn balance(&self, filter: &impl OutpointFilter) -> Amount { self.allocations(filter) .iter() .map(|alloc| alloc.value) - .sum::() + .sum::() } pub fn allocations(&self, filter: &impl OutpointFilter) -> LargeVec { @@ -327,6 +338,11 @@ mod test { assert_eq!(lib.id().to_string(), LIB_ID_RGB20); } + #[test] + fn iface_id() { + assert_eq!(Rgb20::IFACE_ID, rgb20().iface_id()); + } + #[test] fn iface_creation() { rgb20(); } diff --git a/std/src/interface/rgb21.rs b/std/src/interface/rgb21.rs index 8d06805a..215006ed 100644 --- a/std/src/interface/rgb21.rs +++ b/std/src/interface/rgb21.rs @@ -38,7 +38,7 @@ use strict_types::{CompileError, LibBuilder, TypeLib}; use super::{ AssignIface, GenesisIface, GlobalIface, Iface, OwnedIface, Req, TransitionIface, VerNo, }; -use crate::interface::{ArgSpec, ContractIface}; +use crate::interface::{ArgSpec, ContractIface, IfaceId, IfaceWrapper}; use crate::stl::{ rgb_contract_stl, Attachment, Details, DivisibleAssetSpec, MediaType, Name, ProofOfReserves, StandardTypes, Ticker, @@ -414,13 +414,22 @@ pub struct Rgb21(ContractIface); impl From for Rgb21 { fn from(iface: ContractIface) -> Self { - if iface.iface.iface_id != rgb21().iface_id() { + if iface.iface.iface_id != Rgb21::IFACE_ID { panic!("the provided interface is not RGB20 interface"); } Self(iface) } } +impl IfaceWrapper for Rgb21 { + const IFACE_NAME: &'static str = LIB_NAME_RGB21; + const IFACE_ID: IfaceId = IfaceId::from_array([ + 0x04, 0x05, 0x17, 0x86, 0x56, 0x57, 0x1a, 0x21, 0xd4, 0x55, 0xd5, 0xad, 0x0e, 0x0e, 0x5f, + 0x67, 0xd4, 0xb1, 0x76, 0x3f, 0x6e, 0xb3, 0x83, 0x44, 0x80, 0x40, 0x8a, 0x18, 0xd0, 0x14, + 0x30, 0x95, + ]); +} + impl Rgb21 { pub fn spec(&self) -> DivisibleAssetSpec { let strict_val = &self @@ -444,6 +453,11 @@ mod test { assert_eq!(lib.id().to_string(), LIB_ID_RGB21); } + #[test] + fn iface_id() { + assert_eq!(Rgb21::IFACE_ID, rgb21().iface_id()); + } + #[test] fn iface_creation() { rgb21(); } diff --git a/std/src/interface/rgb25.rs b/std/src/interface/rgb25.rs index 4c46301a..b4db5acf 100644 --- a/std/src/interface/rgb25.rs +++ b/std/src/interface/rgb25.rs @@ -31,7 +31,7 @@ use strict_types::{CompileError, LibBuilder, TypeLib}; use super::{ AssignIface, GenesisIface, GlobalIface, Iface, OwnedIface, Req, TransitionIface, VerNo, }; -use crate::interface::{ArgSpec, ContractIface}; +use crate::interface::{ArgSpec, ContractIface, IfaceId, IfaceWrapper}; use crate::stl::{rgb_contract_stl, Amount, ContractData, Details, Name, Precision, StandardTypes}; pub const LIB_NAME_RGB25: &str = "RGB25"; @@ -163,13 +163,22 @@ pub struct Rgb25(ContractIface); impl From for Rgb25 { fn from(iface: ContractIface) -> Self { - if iface.iface.iface_id != rgb25().iface_id() { + if iface.iface.iface_id != Rgb25::IFACE_ID { panic!("the provided interface is not RGB25 interface"); } Self(iface) } } +impl IfaceWrapper for Rgb25 { + const IFACE_NAME: &'static str = LIB_NAME_RGB25; + const IFACE_ID: IfaceId = IfaceId::from_array([ + 0xfa, 0xfd, 0xf4, 0x9e, 0x6a, 0x5d, 0x2f, 0xf5, 0x42, 0xf6, 0x48, 0xb2, 0x64, 0xef, 0x90, + 0xbe, 0x8b, 0x78, 0x85, 0x49, 0x16, 0x5d, 0xc3, 0x6b, 0xc6, 0x83, 0x57, 0x79, 0xb9, 0x37, + 0x73, 0xc4, + ]); +} + impl Rgb25 { pub fn name(&self) -> Name { let strict_val = &self @@ -239,6 +248,11 @@ mod test { assert_eq!(lib.id().to_string(), LIB_ID_RGB25); } + #[test] + fn iface_id() { + assert_eq!(Rgb25::IFACE_ID, rgb25().iface_id()); + } + #[test] fn iface_creation() { rgb25(); } diff --git a/std/src/lib.rs b/std/src/lib.rs index 9289446a..73af684f 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -75,6 +75,12 @@ extern crate strict_encoding; #[cfg(feature = "serde")] #[macro_use] extern crate serde_crate as serde; +#[cfg(feature = "serde")] +#[macro_use] +extern crate serde_with; +#[cfg(feature = "serde")] +#[macro_use] +extern crate cfg_eval; pub use rgb::{contract, schema, validation, vm}; @@ -84,8 +90,17 @@ pub mod containers; pub mod persistence; pub mod resolvers; pub mod accessors; +#[cfg(feature = "descriptor")] +pub mod descriptor; mod reserved; pub use bp::{Chain, Outpoint, Txid}; -use reserved::ReservedBytes; +pub(crate) use reserved::ReservedBytes; +pub use rgb::*; pub use stl::{LIB_NAME_RGB_CONTRACT, LIB_NAME_RGB_STD}; + +/// BIP32 derivation index for outputs which may contain assigned RGB state. +pub const RGB_NATIVE_DERIVATION_INDEX: u32 = 9; +/// BIP32 derivation index for outputs which are tweaked with Tapret commitment +/// and may also optionally contain assigned RGB state. +pub const RGB_TAPRET_DERIVATION_INDEX: u32 = 10; diff --git a/std/src/persistence/inventory.rs b/std/src/persistence/inventory.rs index 0786e595..3344857b 100644 --- a/std/src/persistence/inventory.rs +++ b/std/src/persistence/inventory.rs @@ -38,7 +38,8 @@ use crate::containers::{ Bindle, BuilderSeal, Cert, Consignment, ContentId, Contract, Terminal, Transfer, }; use crate::interface::{ - ContractIface, Iface, IfaceId, IfaceImpl, IfacePair, TransitionBuilder, TypedState, + ContractIface, Iface, IfaceId, IfaceImpl, IfacePair, IfaceWrapper, TransitionBuilder, + TypedState, }; use crate::persistence::hoard::ConsumeError; use crate::persistence::stash::StashInconsistency; @@ -331,7 +332,18 @@ pub trait Inventory: Deref { where R::Error: 'static; - fn contracts_with_iface( + fn contracts_by_iface(&mut self) -> Result, InventoryError> + where + Self::Error: From<::Error>, + InventoryError: From<::Error>, + { + self.contract_ids_by_iface(&W::IFACE_NAME.into())? + .into_iter() + .map(|id| self.contract_iface_wrapped(id)) + .collect() + } + + fn contracts_by_iface_name( &mut self, iface: impl Into, ) -> Result, InventoryError> @@ -343,7 +355,7 @@ pub trait Inventory: Deref { let iface_id = self.iface_by_name(&iface)?.iface_id(); self.contract_ids_by_iface(&iface)? .into_iter() - .map(|id| self.contract_iface(id, iface_id)) + .map(|id| self.contract_iface_id(id, iface_id)) .collect() } @@ -358,10 +370,18 @@ pub trait Inventory: Deref { { let iface = iface.into(); let iface_id = self.iface_by_name(&iface)?.iface_id(); - self.contract_iface(contract_id, iface_id) + self.contract_iface_id(contract_id, iface_id) + } + + fn contract_iface_wrapped( + &mut self, + contract_id: ContractId, + ) -> Result> { + self.contract_iface_id(contract_id, W::IFACE_ID) + .map(W::from) } - fn contract_iface( + fn contract_iface_id( &mut self, contract_id: ContractId, iface_id: IfaceId, diff --git a/std/src/persistence/stock.rs b/std/src/persistence/stock.rs index d502c27f..c7bc1adc 100644 --- a/std/src/persistence/stock.rs +++ b/std/src/persistence/stock.rs @@ -537,7 +537,7 @@ impl Inventory for Stock { self.consume_consignment(contract, resolver, true) } - fn contract_iface( + fn contract_iface_id( &mut self, contract_id: ContractId, iface_id: IfaceId, diff --git a/std/src/stl/specs.rs b/std/src/stl/specs.rs index 0ec351a8..f3ec0407 100644 --- a/std/src/stl/specs.rs +++ b/std/src/stl/specs.rs @@ -22,12 +22,13 @@ #![allow(unused_braces)] // caused by rustc unable to understand strict_dumb use std::fmt; -use std::fmt::{Debug, Formatter}; +use std::fmt::{Debug, Display, Formatter, Write}; use std::iter::Sum; use std::str::FromStr; use amplify::ascii::AsciiString; use amplify::confinement::{Confined, NonEmptyString, NonEmptyVec, SmallOrdSet, SmallString, U8}; +use bp::Sats; use chrono::{DateTime, Local, NaiveDateTime, Utc}; use strict_encoding::stl::{AlphaCapsNum, AsciiPrintable}; use strict_encoding::{ @@ -79,24 +80,96 @@ impl StrictDeserialize for IssueMeta {} derive(Serialize, Deserialize), serde(crate = "serde_crate", transparent) )] -pub struct Amount(u64); +pub struct Amount( + #[from] + #[from(u32)] + #[from(u16)] + #[from(u8)] + #[from(Sats)] + u64, +); impl StrictSerialize for Amount {} impl StrictDeserialize for Amount {} impl Amount { - pub fn zero() -> Self { Amount(0) } - - pub fn one() -> Self { Amount(1) } + pub const ZERO: Self = Amount(0); pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { value.unwrap_uint::().into() } + + pub fn with_precision(amount: u64, precision: impl Into) -> Self { + precision.into().unchecked_convert(amount) + } + + pub fn with_precision_checked(amount: u64, precision: impl Into) -> Option { + precision.into().checked_convert(amount) + } + + pub fn value(self) -> u64 { self.0 } + + pub fn split(self, precision: impl Into) -> (u64, u64) { + let precision = precision.into(); + let int = self.floor(precision); + let fract = self.rem(precision); + (int, fract) + } + + pub fn round(&self, precision: impl Into) -> u64 { + let precision = precision.into(); + let mul = precision.multiplier(); + if self.0 == 0 { + return 0; + } + let inc = 2 * self.rem(precision) / mul; + self.0 / mul + inc + } + + pub fn ceil(&self, precision: impl Into) -> u64 { + let precision = precision.into(); + if self.0 == 0 { + return 0; + } + let inc = if self.rem(precision) > 0 { 1 } else { 0 }; + self.0 / precision.multiplier() + inc + } + + pub fn floor(&self, precision: impl Into) -> u64 { + if self.0 == 0 { + return 0; + } + self.0 / precision.into().multiplier() + } + + pub fn rem(&self, precision: impl Into) -> u64 { + self.0 % precision.into().multiplier() + } + + pub fn saturating_add(&self, other: impl Into) -> Self { + self.0.saturating_add(other.into().0).into() + } + pub fn saturating_sub(&self, other: impl Into) -> Self { + self.0.saturating_sub(other.into().0).into() + } + + pub fn saturating_add_assign(&mut self, other: impl Into) { + *self = self.0.saturating_add(other.into().0).into(); + } + pub fn saturating_sub_assign(&mut self, other: impl Into) { + *self = self.0.saturating_sub(other.into().0).into(); + } +} + +impl Sum for Amount { + fn sum>(iter: I) -> Self { + iter.fold(Amount::ZERO, |sum, value| sum.saturating_add(value)) + } } impl Sum for Amount { fn sum>(iter: I) -> Self { - iter.fold(Amount::zero(), |acc, i| acc + i) + iter.fold(Amount::ZERO, |sum, value| sum.saturating_add(value)) } } @@ -136,10 +209,61 @@ impl StrictDeserialize for Precision {} impl Precision { pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { value.unwrap_enum() } + pub const fn decimals(self) -> u8 { self as u8 } + pub const fn decimals_u32(self) -> u32 { self as u8 as u32 } + + pub const fn multiplier(self) -> u64 { + match self { + Precision::Indivisible => 1, + Precision::Deci => 10, + Precision::Centi => 100, + Precision::Milli => 1000, + Precision::DeciMilli => 10_000, + Precision::CentiMilli => 100_000, + Precision::Micro => 1_000_000, + Precision::DeciMicro => 10_000_000, + Precision::CentiMicro => 100_000_000, + Precision::Nano => 1_000_000_000, + Precision::DeciNano => 10_000_000_000, + Precision::CentiNano => 100_000_000_000, + Precision::Pico => 1_000_000_000_000, + Precision::DeciPico => 10_000_000_000_000, + Precision::CentiPico => 100_000_000_000_000, + Precision::Femto => 1_000_000_000_000_000, + Precision::DeciFemto => 10_000_000_000_000_000, + Precision::CentiFemto => 100_000_000_000_000_000, + Precision::Atto => 1_000_000_000_000_000_000, + } + } + + pub fn unchecked_convert(self, amount: impl Into) -> Amount { + (amount.into() * self.multiplier()).into() + } + + pub fn checked_convert(self, amount: impl Into) -> Option { + amount + .into() + .checked_mul(self.multiplier()) + .map(Amount::from) + } + pub fn saturating_convert(self, amount: impl Into) -> Amount { + amount.into().saturating_mul(self.multiplier()).into() + } } -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] -#[display("{int}.{fract}")] +impl From for u16 { + fn from(value: Precision) -> Self { value as u8 as u16 } +} + +impl From for u32 { + fn from(value: Precision) -> Self { value as u8 as u32 } +} + +impl From for u64 { + fn from(value: Precision) -> Self { value as u8 as u64 } +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct CoinAmount { pub int: u64, pub fract: u64, @@ -147,10 +271,10 @@ pub struct CoinAmount { } impl CoinAmount { - pub fn with(value: u64, precision: Precision) -> Self { - let pow = 10_u64.pow(precision as u32); - let int = value / pow; - let fract = value - int * pow; + pub fn with(value: impl Into, precision: impl Into) -> Self { + let precision = precision.into(); + let value = value.into(); + let (int, fract) = value.split(precision); CoinAmount { int, fract, @@ -159,6 +283,47 @@ impl CoinAmount { } } +impl Display for CoinAmount { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut int = self.int.to_string(); + if f.alternate() { + int = int + .chars() + .rev() + .collect::() + .as_bytes() + .chunks(3) + .map(<[u8]>::to_owned) + .map(|mut chunk| unsafe { + chunk.reverse(); + String::from_utf8_unchecked(chunk) + }) + .rev() + .collect::>() + .join("`"); + } + f.write_str(&int)?; + if self.fract > 0 { + f.write_char('.')?; + let mut float = self.fract.to_string(); + let len = float.len(); + if let Some(decimals) = f.precision() { + float.extend("0".repeat(decimals - len).chars()); + } + if f.alternate() { + float = float + .as_bytes() + .chunks(3) + .map(|chunk| unsafe { String::from_utf8_unchecked(chunk.to_owned()) }) + .collect::>() + .join("`"); + } + f.write_str(&float)?; + } + Ok(()) + } +} + #[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] #[wrapper(Deref, Display)] #[derive(StrictDumb, StrictType, StrictDecode)] @@ -369,7 +534,7 @@ impl Debug for Details { } } -#[derive(Clone, Eq, PartialEq, Debug)] +#[derive(Clone, Eq, PartialEq, Hash, Debug)] #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_CONTRACT)] #[cfg_attr( @@ -425,7 +590,7 @@ impl AssetNaming { } } -#[derive(Clone, Eq, PartialEq, Debug)] +#[derive(Clone, Eq, PartialEq, Hash, Debug)] #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_CONTRACT)] #[cfg_attr( @@ -477,7 +642,8 @@ impl DivisibleAssetSpec { pub fn details(&self) -> Option<&str> { self.naming.details.as_ref().map(|d| d.as_str()) } } -#[derive(Clone, Eq, PartialEq, Debug, Default)] +#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Default)] +#[display(inner)] #[derive(StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_CONTRACT)] #[cfg_attr( @@ -498,7 +664,7 @@ impl FromStr for RicardianContract { } } -#[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug, From)] +#[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Deref, Display, FromStr, MathOps)] #[wrapper_mut(DerefMut, MathAssign)] #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] @@ -562,7 +728,7 @@ impl Attachment { } } -#[derive(Clone, Eq, PartialEq, Debug)] +#[derive(Clone, Eq, PartialEq, Hash, Debug)] #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_CONTRACT)] #[cfg_attr( @@ -595,9 +761,10 @@ mod test { #[test] fn coin_amount() { - let amount = CoinAmount::with(10_000_436_081_95, Precision::default()); + let amount = CoinAmount::with(10_000_436_081_95u64, Precision::default()); assert_eq!(amount.int, 10_000); assert_eq!(amount.fract, 436_081_95); assert_eq!(format!("{amount}"), "10000.43608195"); + assert_eq!(format!("{amount:#.10}"), "10`000.436`081`950`0"); } } diff --git a/stl/Cargo.toml b/stl/Cargo.toml new file mode 100644 index 00000000..e1038055 --- /dev/null +++ b/stl/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "rgb-stl" +version = "0.11.0-alpha" +description = "RGB strict type libraries" +keywords = ["bitcoin", "lightning", "rgb", "smart-contracts", "lnp-bp"] +categories = ["cryptography::cryptocurrencies"] +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +rust-version = { workspace = true } +readme = "../README.md" + +[[bin]] +name = "rgb-stl" +path = "src/main.rs" + +[dependencies] +strict_types = { workspace = true } +rgb-std = { version = "0.11.0-alpha", path = "../std" } diff --git a/std/src/bin/rgb-stl.rs b/stl/src/main.rs similarity index 96% rename from std/src/bin/rgb-stl.rs rename to stl/src/main.rs index 139409f3..7593d1ff 100644 --- a/std/src/bin/rgb-stl.rs +++ b/stl/src/main.rs @@ -20,8 +20,8 @@ // 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::stl::{rgb_contract_stl, rgb_std_stl}; +use rgb::interface::{rgb20_stl, rgb21_stl, rgb25_stl}; +use rgb::stl::{rgb_contract_stl, rgb_std_stl}; use strict_types::parse_args; fn main() {