diff --git a/.rustfmt.toml b/.rustfmt.toml index 9017cd7..6d14899 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,5 +1,5 @@ edition = "2021" -version = "Two" +style_edition = "2021" max_width = 100 array_width = 100 diff --git a/Cargo.lock b/Cargo.lock index 2b691cd..b764046 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,8 @@ version = 3 [[package]] name = "aluvm" -version = "0.11.0-beta.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db04c1d697d7f5b86d935bfe06cfd0310fd8a6c491b043118bec228597dcede9" +version = "0.11.0-beta.9" +source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#7adf61dbe4a3b39834bc3d665800024d66658e9c" dependencies = [ "amplify", "ascii-armor", @@ -34,7 +33,6 @@ dependencies = [ "amplify_num", "amplify_syn", "ascii", - "rand", "serde", "stringly_conversions", "wasm-bindgen", @@ -101,9 +99,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -135,9 +133,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "baid64" @@ -173,10 +171,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] -name = "bitcoin-private" -version = "0.1.0" +name = "bitcoin-io" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] [[package]] name = "bitflags" @@ -214,8 +222,8 @@ dependencies = [ [[package]] name = "bp-consensus" -version = "0.11.0-beta.8" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#6ae56d5a005f0e0fc761516fb96c2c47bb13de46" +version = "0.11.0-beta.9" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#0f591b4bcbd16d4bab3c9fe7134b9eaf8d397023" dependencies = [ "amplify", "chrono", @@ -228,8 +236,8 @@ dependencies = [ [[package]] name = "bp-core" -version = "0.11.0-beta.8" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#6ae56d5a005f0e0fc761516fb96c2c47bb13de46" +version = "0.11.0-beta.9" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#0f591b4bcbd16d4bab3c9fe7134b9eaf8d397023" dependencies = [ "amplify", "bp-consensus", @@ -246,8 +254,8 @@ dependencies = [ [[package]] name = "bp-dbc" -version = "0.11.0-beta.8" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#6ae56d5a005f0e0fc761516fb96c2c47bb13de46" +version = "0.11.0-beta.9" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#0f591b4bcbd16d4bab3c9fe7134b9eaf8d397023" dependencies = [ "amplify", "base85", @@ -260,9 +268,8 @@ dependencies = [ [[package]] name = "bp-invoice" -version = "0.11.0-beta.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29c4f672b4b82ce7a218b2900254ac8e4b15b0022ed13abffa722571e73d375" +version = "0.11.0-beta.9" +source = "git+https://github.com/BP-WG/bp-std?branch=develop#b83739dc1ee3299a85f4cb040e061597dd9be2db" dependencies = [ "amplify", "bech32", @@ -272,8 +279,8 @@ dependencies = [ [[package]] name = "bp-seals" -version = "0.11.0-beta.8" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#6ae56d5a005f0e0fc761516fb96c2c47bb13de46" +version = "0.11.0-beta.9" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#0f591b4bcbd16d4bab3c9fe7134b9eaf8d397023" dependencies = [ "amplify", "baid64", @@ -300,9 +307,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.16" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d013ecb737093c0e86b151a7b837993cf9ec6c502946cfb44bedc392421e0b" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "shlex", ] @@ -330,9 +337,8 @@ dependencies = [ [[package]] name = "commit_encoding_derive" -version = "0.11.0-beta.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea07c5ad73a637276dc4f8a957f8285764018d45bdefef35eb9137f32d0e3c81" +version = "0.11.0-beta.9" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#4015f1fb9e99fdc536c69b957fa5727da9cfa6a9" dependencies = [ "amplify", "amplify_syn", @@ -343,9 +349,8 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.11.0-beta.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a1982dc6c54d2dcfa2bf4398d97e4e80a93f24d2537e58d6110b2b272cff0c" +version = "0.11.0-beta.9" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#4015f1fb9e99fdc536c69b957fa5727da9cfa6a9" dependencies = [ "amplify", "commit_encoding_derive", @@ -382,9 +387,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -421,12 +426,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "fast32" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ea9bdb2356e5a92403cf23ac493f9b43bd71e4ffd0f800862b841dd723994c" - [[package]] name = "fluent-uri" version = "0.1.4" @@ -471,9 +470,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] name = "heck" @@ -481,11 +480,20 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -506,12 +514,13 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown", + "serde", ] [[package]] @@ -522,18 +531,18 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.158" +version = "0.2.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "f0b21006cd1874ae9e650973c565615676dc4a274c965bb0a73796dac838ce4f" [[package]] name = "log" @@ -547,12 +556,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "minicov" version = "0.3.5" @@ -571,9 +574,9 @@ checksum = "f2b8f3a258db515d5e91a904ce4ae3f73e091149b90cadbdb93d210bee07f63b" [[package]] name = "nonasync" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94a84b7c873630913f738950f17412b9d5b24cad6866b98b802253f8cbbefabb" +checksum = "4b1005555d351f593bf72ffc3a89a0d42e243df004d2c4ded17699f10b562b98" dependencies = [ "amplify", ] @@ -589,9 +592,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "paste" @@ -616,9 +619,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -664,18 +667,17 @@ dependencies = [ [[package]] name = "rgb-core" -version = "0.11.0-beta.8" -source = "git+https://github.com/RGB-WG/rgb-core?branch=develop#0450760dbae554de0d7623691aed7630f1b60a60" +version = "0.11.0-beta.9" +source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#9c6f3fee4ac573380c0ed8658d644fc5a7cfc533" dependencies = [ "aluvm", "amplify", "baid64", + "base64", "bp-core", "chrono", "commit_verify", "getrandom", - "mime", - "secp256k1-zkp", "serde", "single_use_seals", "strict_encoding", @@ -705,14 +707,13 @@ dependencies = [ [[package]] name = "rgb-invoice" -version = "0.11.0-beta.8" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#796312c89122607ff77dd41c5cffeb34db472d34" +version = "0.11.0-beta.9" +source = "git+https://github.com/RGB-WG/rgb-std?branch=feat/fungible-nonconf#0bf8c97606d081b65a6d74f21f854c997246bf8d" dependencies = [ "amplify", "baid64", "bp-core", "bp-invoice", - "fast32", "fluent-uri", "indexmap", "percent-encoding", @@ -720,13 +721,12 @@ dependencies = [ "rgb-core", "serde", "strict_encoding", - "strict_types", ] [[package]] name = "rgb-std" -version = "0.11.0-beta.8" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#796312c89122607ff77dd41c5cffeb34db472d34" +version = "0.11.0-beta.9" +source = "git+https://github.com/RGB-WG/rgb-std?branch=feat/fungible-nonconf#0bf8c97606d081b65a6d74f21f854c997246bf8d" dependencies = [ "aluvm", "amplify", @@ -780,10 +780,11 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "secp256k1" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ + "bitcoin_hashes", "rand", "secp256k1-sys", "serde", @@ -791,54 +792,31 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] -[[package]] -name = "secp256k1-zkp" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a44aed3002b5ae975f8624c5df3a949cfbf00479e18778b6058fcd213b76e3" -dependencies = [ - "bitcoin-private", - "rand", - "secp256k1", - "secp256k1-zkp-sys", - "serde", -] - -[[package]] -name = "secp256k1-zkp-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6eea7919e0cab992510edfbf40bd9342c0a3c2bb910f2c51355c2cb2d69839" -dependencies = [ - "cc", - "secp256k1-sys", -] - [[package]] name = "serde" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -855,9 +833,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -904,9 +882,8 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" -version = "0.11.0-beta.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1a4c51f21507cf63984c367507f281215073e85b08711ed7da4fc63dbd709e0" +version = "0.11.0-beta.9" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#4015f1fb9e99fdc536c69b957fa5727da9cfa6a9" dependencies = [ "amplify_derive", ] @@ -939,9 +916,8 @@ dependencies = [ [[package]] name = "strict_types" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f16e8855a575633815f01482ac927ebaca3d2485aec8e17226c6826de29154e" +version = "2.7.1" +source = "git+https://github.com/strict-types/strict-types?branch=develop#729a4f86d25dfcea15ed15bbeb1e027473401c58" dependencies = [ "amplify", "ascii-armor", @@ -981,9 +957,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -992,22 +968,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1033,9 +1009,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", @@ -1052,9 +1028,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unsafe-libyaml" @@ -1096,9 +1072,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -1107,24 +1083,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -1134,9 +1110,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1144,28 +1120,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-bindgen-test" -version = "0.3.43" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9" +checksum = "d381749acb0943d357dcbd8f0b100640679883fcdeeef04def49daf8d33a5426" dependencies = [ "console_error_panic_hook", "js-sys", @@ -1178,20 +1154,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.43" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" +checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -1290,9 +1266,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -1315,5 +1291,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] diff --git a/Cargo.toml b/Cargo.toml index faa846b..dae1bc9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,14 +22,15 @@ name = "ifaces" [dependencies] amplify = "4.7.0" strict_encoding = "2.7.0" -strict_types = "2.7.0" -aluvm = "0.11.0-beta.8" -bp-core = "0.11.0-beta.8" -rgb-std = { version = "0.11.0-beta.8" } +strict_types = "2.7.1" +aluvm = "0.11.0-beta.9" +bp-core = "0.11.0-beta.9" +rgb-std = { version = "0.11.0-beta.9" } chrono = "0.4.38" serde_crate = { package = "serde", version = "1.0", optional = true } serde_json = "1.0" sha2 = "0.10.8" +rand = "0.8.5" [features] default = [] @@ -49,10 +50,15 @@ wasm-bindgen-test = "0.3" features = ["all"] [patch.crates-io] +commit_verify = { git = "https://github.com/LNP-BP/client_side_validation", branch = "develop" } +single_use_seals = { git = "https://github.com/LNP-BP/client_side_validation", branch = "develop" } +strict_types = { git = "https://github.com/strict-types/strict-types", branch = "develop" } +aluvm = { git = "https://github.com/AluVM/rust-aluvm", branch = "develop" } bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } -rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "develop" } -rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "develop" } -rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "develop" } +bp-invoice = { git = "https://github.com/BP-WG/bp-std", branch = "develop" } +rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "feat/fungible-nonconf" } +rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "feat/fungible-nonconf" } +rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "feat/fungible-nonconf" } diff --git a/interfaces/RGB20.rgba b/interfaces/RGB20.rgba index 7d37499..2cf519b 100644 --- a/interfaces/RGB20.rgba +++ b/interfaces/RGB20.rgba @@ -1,9 +1,14 @@ -----BEGIN RGB KIT----- +<<<<<<< Updated upstream Id: rgb:kit:rkBGk37g-KX3CPhg-4kytJa3-FI7gQJG-rPElGuq-Ya3vC$Y +======= +Id: rgb:kit:Oxiw5RWf-vJ5prS7-uT4aNXn-XxZzy5F-Z6OijII-aQLAaX0 +>>>>>>> Stashed changes Version: 2 Interface: RGB20InflatableBurnable; id=BWy2H0Nd-ykgandr-mR5fydi-U$7tFU2-R!z1F9B-MZW0tKo#bishop-poem-dublin; dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; +<<<<<<< Updated upstream suppl=hwNKARI0FMsV5mr8LTkJaAMSlxQo2x5LP6WdvGTZoBs Interface: RGB20RenamableBurnable; id=FFfPPWDH-4$BWBn7-3QnE8WV-nHj98E8-IoAIZvt-4kiX7YA#theory-memo-puzzle; @@ -43,6 +48,47 @@ Interface: RGB20Fixed; suppl=vs0oZVfUdW73Bxno8ebclKF6k1hCoxTJxPYrumSZQxQ Type-System: sts:3Vut1$G8-lmJY9!z-CvaNdjp-n0adNAj-IVQQ1jB-SdhQxp4#parker-axiom-meaning Check-SHA256: 7bb82626cf537cdf39f60d103a509a6e856f00a8e4aebd059d845fed467de585 +======= + suppl=89U79jb26Gncve7M7F4UUCpk6UIOkWhJzG8RKvKWtEM +Interface: RGB20RenamableBurnable; + id=FFfPPWDH-4$BWBn7-3QnE8WV-nHj98E8-IoAIZvt-4kiX7YA#theory-memo-puzzle; + dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; + suppl=miIOUHR0uzxxNMoU!AYv3YjM1vXOtcfoE131n$xXxXk +Interface: RGB20RenamableInflatable; + id=Gzd3DwVy-TtF3Z6V-h981qjU-WV9QmbS-$SB5Tyg-6y5PLPc#battery-consul-mercury; + dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; + suppl=hMXvyScQyPGyQLsQ13Ccgu5Rkj2eQFk9pZ33MH9lTqg +Interface: RGB20RenamableInflatableBurnable; + id=MkSuvvz2-StGzuV8-Hewq0fo-hMigWm$-UMxXtdP-RCnZyec#asia-domino-respect; + dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; + suppl=AaSx0n$zumRWzsibk8D!o4hqe0PaixmJpdqkKhM6JSY +Interface: RGB20Inflatable; + id=YLpmbnY2-yZn$JdG-ghjwoCP-zj215y0-$XuwA90-o$CP$pg#camel-slogan-comrade; + dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; + suppl=$BdZn!VE9pdtbHjTliPlT6nxO0ncdiFMy!mvNCcveJY +Interface: RGB20RenamableFixed; + id=meHrtVTZ-6xAdd0w-rjDttLh-cs2n7zn-sZBzfwz-FcU!i24#jungle-wizard-dollar; + dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; + suppl=c3HHWKFzw1j4PX6aIrgtu1bPpSDEQKSLZIZWMe98uQ4 +Interface: RGB20RenamableReplaceable; + id=r6$dLeVy-H0HQpUy-F2XbX2E-P2JqbHp-wsISD4f-xUEaOKQ#postage-plaza-almond; + dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; + suppl=y6IUIBLvpvlHXSqwQBY07g1FCOIf8OM2h6FoMPk7AKs +Interface: RGB20Replaceable; + id=w0Z1Za2j-klpfWyT-4coOB!6-90qakW5-AfjmIc9-ejZbKZU#cycle-buzzer-british; + dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; + suppl=b1JpYooFEQCqTF8LQJ5t5aEzON0aAZ$zOHM0qitdSV4 +Interface: RGB20Burnable; + id=yxQRcNJ4-yMnJ0$c-gLjwpdS-8DuJjFn-pWQ4i5C-To2R$U4#basil-gopher-music; + dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; + suppl=NhFnLmqm2Y$!m1OevVPCMVVk0oI3QTVS3Vz1KeJiyQA +Interface: RGB20Fixed; + id=$iUnO9aO-1xhqUd6-1Jm5S5!-wM3ngby-5GVEylQ-ZTAMYDk#tornado-pioneer-bucket; + dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; + suppl=!T7tB8o2PZg9jESy5TKq9olEj66QySkMVVpG1rkp!bk +Type-System: sts:3Vut1$G8-lmJY9!z-CvaNdjp-n0adNAj-IVQQ1jB-SdhQxp4#parker-axiom-meaning +Check-SHA256: d585fc34c69c09b94548b30d30e1f95959b0e741084b9f3a7b16df85e0928420 +>>>>>>> Stashed changes 0tx{aQb$5EFiCD^Y+-a^Vr*qXb#iWDVr*pwR!>~x^Kusb3F_D>3|%=0P4(JM3 91~BkJ``pp2L<+WYM!zJb=Ey6LPIrKAc+<}ouO+1_y#HazXRttFXqDki#07`P*;L4`>n3v9olck(HKSg @@ -266,6 +312,7 @@ W@%+)AYpSLVIXI0Z(?C=AaG%FVQpn}WpW^7Z)J0CCv+ffVRU0?AarPDAZc@Rb!B8Ab9HcVYK5Ib#!obbaONSb8~4rOj=Vhb$BgjYD771 SWreSPh(|tRaI+OEjDs9byGuAHZ5UMXmdGNHD)b1N<}w!000UC1#Gq-LtV;98lBqaN0;(;B|q-bRM{W1 +<<<<<<< Updated upstream )L%g{m9(^~pY!cz00000GyrpRX*x_=Q!#aTEoW*(Ic```MlDZcWpq_lYga8cax-;PLsK>_VNqyvIaf7i EjUU=H+KO50RRFBMrC1ib#i5M6#xPVVs&zEVPb4$3TbX;Y+-a^Vr*pyQ*>c&WMOh-1^@+8M?x|%0u)!z Jz&S<@Ky$X_d;_VNqyvIaf7iEjUU=H+KO50RRFBMrC1ib#i5MApipiVs&zEVPb4$ km4>vPK}ZMPM`DbW&i*H05kw|b7?wET2nD~cr9mYL^*C)P)03JV`X$zRclu*HgYp{Q$tfWEn!h;b2(Qv W-T~MMK^Z=009632u5XLbairNa|!?f2x4_|Zee0_VNqyvIaf7i +EjUU=H+KO50RRFBMrC1ib#i5M6#xPVVs&zEVPb4$3TbX;Y+-a^Vr*pyQ*>c&WMOh-1^@+8M?x|%0u)!z +Jz&S<@Ky$X_d;c&WMOh-1^@+8M?x|%0vk7X4+U~g(RXL1VfW2yjYXC937bpwf#p1)>n=|$_tkXaW&i*H05kw|b7?wE +T2nD~cr9mYL^*C)P)03JV`X$zRclu*HgYp{Q$tfWEn!h;b2(QvW-T~MMK^Z=009632u5XLbairNa~1#s +3TbX;Y+-a^Vr*pza%FB|ZDC?;We8JrVQyq$a%2Vo1yV;sGB5%%M6SO4_Da#SxnBo+3bcNROo|1j{X;Qc +*H1(#*~#bCbm3+I0000q0CRI`I!szqF?Dz?XKF+_Zdg!8El*=*bX8SrS1mSjGj&r#Q#LJOQD}2HS2boW +I7&q~cL4wa00Ia`Wnpx6a%FQL00RhOb#iWDVr*p!X>Mk0VRT_)Y-I^@Wo}_@VPb4$2vc-nZe(F{WCj2Q +Qb$5EFalt@W^Q&i$(jEp(V&JrC$Ozb>ku7xOe>5#Z7vrq+J5t%#zD>eGZn=?i*D6);bs5;001-qb8~4r +Oj=Vhb$BgjYD771SWreSPh(|tRaI+OEjDs9byGuAHZ5UMXmdGNHD)b1N<}w!0RRC20tiNBVRUtJWpfJv +0SR(tZeeXc&WMOh-1^@+8M?x|%0jbYX5}VRB>! +00mM_VNqyvIaf7iEjUU=H+KO50RRFBMrC1ib#i5MApipiVs&zEVPb4$ +3TbX;Y+-a^Vr*p#a%FIAVPj=sVr*pyQ*>c&WMOh-1^@+8M?x|%0?QN;aMF0l$;s3AATB&9buRvPK}ZMPStebW&i*H05kw|b7?wET2nD~cr9mYL^*C)P)03JV`X$zRclu*HgYp{Q$tfWEn!h;b2(Qv +W-T~MMK^Z=009632u5XLbairNa|!?f2x4_|Zee0>>>>>> Stashed changes Q#LJOQD}2HS2boWI7&q~cL4wa00Ia`Wnpx6a%FP?000P6bYX5}VRB>!00mMUMA(m1w0!?L{VGDpk+OvDhHAKF%fNXr25$w;Zs!r0000000007 000000000E(i%G%h4}Sf8vn;89aSG|t4s0*&BRFk%a^yrND0jb0t9t*cyH)xK+Rkw`Mu(V|7oQWGN(Z+ diff --git a/interfaces/RGB21.rgba b/interfaces/RGB21.rgba index b5f61ef..4fa57a4 100644 --- a/interfaces/RGB21.rgba +++ b/interfaces/RGB21.rgba @@ -1,9 +1,14 @@ -----BEGIN RGB KIT----- +<<<<<<< Updated upstream Id: rgb:kit:NYvLHd4g-aog4Oz$-ZjWJJtz-iKdOImJ-9U9tH10-hWBvQgo +======= +Id: rgb:kit:t6NBduZk-TuPvLg2-Ne!Ssrd-ftLpSGh-$3DjG9B-Qs6mDms +>>>>>>> Stashed changes Version: 2 Interface: RGB21Issuable; id=MTbC0xIy-t4kjnRO-6lrefMT-QDDxtSN-SNOHen$-WEeyyfc#cubic-motif-corona; dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; +<<<<<<< Updated upstream suppl=ZHXpK8I4SysWFz3LQLfshLbo4RLUWBnSiCt2uU4$q84 Interface: RGB21Unique; id=zaiUh27F-2cYWfcd-FfL5lBc-uUenO66-IYZE0D9-GeVIvGU#forest-heroic-energy; @@ -11,6 +16,15 @@ Interface: RGB21Unique; suppl=LDm0JMzpP1yeC!0J0mCjIA4r0WLxzr8aMnXR98haDLI Type-System: sts:khmpaMuX-TkN$aWG-9khkPeS-s7byD4Q-VtuwEzF-2bqkUZc#alien-phone-bagel Check-SHA256: 96812bdd94b205ee024b5c0b50c3feaa3d42d582662d97f37c4088337b764c44 +======= + suppl=a1Q4zFnYqxm0UNKC8QFT3YxCuPW1VOXxXd6C6PS1vbc +Interface: RGB21Unique; + id=zaiUh27F-2cYWfcd-FfL5lBc-uUenO66-IYZE0D9-GeVIvGU#forest-heroic-energy; + dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; + suppl=MfxvE6131d3fIuvs5MwkvWtq3eDttBK0wt3Oc88rP8o +Type-System: sts:khmpaMuX-TkN$aWG-9khkPeS-s7byD4Q-VtuwEzF-2bqkUZc#alien-phone-bagel +Check-SHA256: 0daf544cf859c57c6e184ddb4b098aac6b1bffe32cc205e138561add186b5176 +>>>>>>> Stashed changes 0s;XIQb$5EF-dcCbzx#`We8SJT;ua{7X1n8*eMKMIS5Vl+JKgY@eMZUni+<~yI*pqgJC?_Ngk-C4>AJ< *4uOk<_EsKqDt~i^2VW=;sVUJc^^_AA?HnP4dl)m7&~2db~aWFA>JNQ2jD2sV9r$e#NPRGODlp?H>{w_ @@ -59,9 +73,15 @@ AY^Z4b8aVeAZ2lNVQe6DZyV?GAZczOZ*_EVb#!wQZf|Zza$#e1 X>V>}Y*cS+Wo|fObaZ8HaC9JaZyb#7~JZ+C7~Z);_49${>3Z)0I}X>V>IZ)PBMZfkCDcWxkbZ);_4AW1|t0CRI`I!szqF?Dz?XKF+_ Zdg!8El*=*bX8SrS1mSjGj&r#Q#LJOQD}2HS2boWI7&q~cK`qa0x>qi(-Jbbi6fm8x|X+}F*E}Y8&WkR +<<<<<<< Updated upstream P95q0SVywS_n`CbW&i*H05kw|b7?wET2nD~cr9mYL^*C)P)03JV`X$zRclu*HgYp{Q$tfWEn!h;b2(Qv W-T~MMK^Z=009632u5XLbairNb1VP^3S)0V={Wo~D3VRm6+Y-I{&a$#e1X>V>}YzcB@ZeeX< Vr*pyQ*>c&WMOh-1^@+8M?x|&0?nwDhi=8$#uk0YMSQ+x1V={Wo~D3VRm6+Y-I{&a$#e1X>V>}YzcB@ZeeX< +Vr*pyQ*>c&WMOh-1^@+8M?x|&0?nwDhi=8$#uk0YMSQ+x1>>>>>> Stashed changes b7?wET2nD~cr9mYL^*C)P)03JV`X$zRclu*HgYp{Q$tfWEn!h;b2(QvW-T~MMK^Z=009632u5XLbairN a}xjp3TAR)V{~b6ZeeT&b#7^Kb!7-sbYX5}VRB>!00mMUMA(m1w0!?L{VGDpk+OvDhHAKF%fNXr25$w;Zs!r0000000007000000000Es;(M& diff --git a/interfaces/RGB25.rgba b/interfaces/RGB25.rgba index b0023c6..49332eb 100644 --- a/interfaces/RGB25.rgba +++ b/interfaces/RGB25.rgba @@ -1,9 +1,14 @@ -----BEGIN RGB KIT----- +<<<<<<< Updated upstream Id: rgb:kit:8mXeEnUx-EyzZlTk-0MO3Cl7-seOaZ7A-pd88Ig2-J!pAl!E +======= +Id: rgb:kit:6LCevgpV-$k2cmRp-q6n3NUM-T0gysIh-t6fptqh-PIQALek +>>>>>>> Stashed changes Version: 2 Interface: RGB25Base; id=BdKiMHub-RZTYrbS-13G3wt6-4uIchyP-MQF0Kmm-sYgeMkY#prism-cobalt-airport; dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; +<<<<<<< Updated upstream suppl=CmqfSmozlZRuQtv9v5Ub3pNh2lDomOB!30nhusj9S1M Interface: RGB25Burnable; id=CQLcyFgc-TMChxZQ-6$8Owdz-HOytrmh-T9QD8tL-eHy8ZUE#raymond-promise-bamboo; @@ -11,6 +16,15 @@ Interface: RGB25Burnable; suppl=w6hyCHL1$WIjv27xAalSxjRgjPKppI1ySZp86Q7zkMs Type-System: sts:3pzOQ8jc-nE9lsSp-a51hPfv-xeYwyK0-evp1qcM-rR!COak#wedding-gong-mental Check-SHA256: 38d5a4c3eefc5517d9a5b2f12ca4070150373b32c31e6d00529d9d0f0b0eba3f +======= + suppl=1WjLblTHXbTdj1g3oZIOStriXl!nL2mdYGjq!bfA3Yo +Interface: RGB25Burnable; + id=CQLcyFgc-TMChxZQ-6$8Owdz-HOytrmh-T9QD8tL-eHy8ZUE#raymond-promise-bamboo; + dev=ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w; + suppl=dhKxO1HeYPARyGFcTf1cKzGuXuKQisxAlyicgENlgbE +Type-System: sts:3pzOQ8jc-nE9lsSp-a51hPfv-xeYwyK0-evp1qcM-rR!COak#wedding-gong-mental +Check-SHA256: c9e9c2b9e8607a07625b1a535c5a95b2c363eaf749e1720a58b141cc5289fa43 +>>>>>>> Stashed changes 0s;XEQb$5EH9}!?WdefyeA22rmXX)ZV_yI}MH~YN>;K=mRmV)&;+=Xmp=8%{dOaKyPp>`{W+ev&_Ht^T vI2G1Jtsm#HCZ5u7Cwae0cHRI0000617UJ>0e1iJJu1QEX=%Xy>vn1>teUKtq)w3djjO=VIO}{ZUjP6H @@ -44,9 +58,15 @@ YK5Ib#!obbaONSb8~4rOj=Vh b$BgjYD771SWreSPh(|tRaI+OEjDs9byGuAHZ5UMXmdGNHD)b1N<}w!000641=6B0dz(d+*sZj++->l; +<<<<<<< Updated upstream t}Y?Say-NZ(5a@eh#oRVp!4l!00000GyrpRX*x_=Q!#aTEoW*(Ic```MlDZcWpq_lYga8cax-;PLsK>_ VNqyvIaf7iEjUU=H+KO50RRFBMrC1ib#i5M3;+QNW^!R;bZKvHVQdIfbYX5}VRB>!00mM_ +VNqyvIaf7iEjUU=H+KO50RRFBMrC1ib#i5M3;+QNW^!R;bZKvHVQdIfbYX5}VRB>!00mM>>>>>> Stashed changes Yga8cax-;PLsK>_VNqyvIaf7iEjUU=H+KO50RRFBMrC1ib#i5M6#xPVVs&zEVPb4$3TAR)V{~b6ZeeT) Q*>c&WMOh-1^@+8M?x|+C;$Ks(i%G%h4}Sf8vn;89aSG|t4s0*&BRFk%a^yrND0jb0t9t*cyH)xK+Rkw `Mu(V|7oQWGN(Z+AyvH&RuaL#D^138|7M^`NNc{jXEg#>2x#JO!0is)`buE3*f$s=7 diff --git a/src/lib.rs b/src/lib.rs index 8107073..4b9b249 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,12 +24,13 @@ #[macro_use] extern crate amplify; #[macro_use] -extern crate strict_types; +extern crate strict_encoding; #[cfg(feature = "serde")] #[macro_use] extern crate serde_crate as serde; mod traits; +pub mod stl; pub mod rgb20; pub mod rgb21; @@ -38,6 +39,7 @@ pub mod rgb25; pub use rgb20::{Rgb20, Rgb20Info, Rgb20Wrapper}; pub use rgb21::{Rgb21, Rgb21Wrapper}; pub use rgb25::{Rgb25, Rgb25Info, Rgb25Wrapper}; +pub use stl::{LIB_ID_RGB_CONTRACT, LIB_NAME_RGB_CONTRACT}; pub use traits::{IssuerWrapper, SchemaIssuer}; pub const LNPBP_IDENTITY: &str = "ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w"; diff --git a/src/main.rs b/src/main.rs index d7c9cbf..c1ab75d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,13 +25,14 @@ use std::path::PathBuf; use std::str::FromStr; use std::{fs, io}; +use ifaces::stl::rgb_contract_stl; use ifaces::{rgb20, rgb21, rgb25, Rgb20, Rgb21, LNPBP_IDENTITY}; use rgbstd::containers::{ FileContent, Kit, Supplement, SUPPL_ANNOT_IFACE_CLASS, SUPPL_ANNOT_IFACE_FEATURES, }; use rgbstd::info::IfaceClassName; use rgbstd::interface::IfaceClass; -use rgbstd::stl::{bp_tx_stl, rgb_contract_stl}; +use rgbstd::stl::bp_tx_stl; use strict_types::stl::std_stl; use strict_types::{StlFormat, SystemBuilder}; @@ -148,6 +149,28 @@ fn main() -> io::Result<()> { ) .expect("unable to write to the file"); + let contract_stl = rgb_contract_stl(); + contract_stl + .serialize(StlFormat::Binary, Some(&dir), "0.11.0", None) + .expect("unable to write to the file"); + contract_stl + .serialize(StlFormat::Armored, Some(&dir), "0.11.0", None) + .expect("unable to write to the file"); + contract_stl + .serialize( + StlFormat::Source, + Some(&dir), + "0.11.0", + Some( + " + Description: Types for writing RGB contracts and interfaces + Author: Dr Maxim Orlovsky + Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. + License: Apache-2.0", + ), + ) + .expect("unable to write to the file"); + let mut filename = dir.clone(); let mut map = HashMap::new(); diff --git a/src/rgb20/iface.rs b/src/rgb20/iface.rs index 7038cb4..01b14db 100644 --- a/src/rgb20/iface.rs +++ b/src/rgb20/iface.rs @@ -20,13 +20,12 @@ // limitations under the License. use rgbstd::interface::{ - AssignIface, GenesisIface, GlobalIface, Iface, Modifier, OwnedIface, Req, TransitionIface, - VerNo, + AssignIface, GenesisIface, GlobalIface, Iface, Modifier, TransitionIface, VerNo, }; use rgbstd::schema::Occurrences; -use rgbstd::stl::StandardTypes; use rgbstd::Identity; +use crate::stl::StandardTypes; use crate::LNPBP_IDENTITY; pub fn rgb20_base() -> Iface { named_asset().expect_extended(fungible(), tn!("RGB20Base")) } @@ -77,7 +76,7 @@ pub fn renameable() -> Iface { metadata: none!(), global_state: none!(), assignments: tiny_bmap! { - fname!("updateRight") => AssignIface::public(OwnedIface::Rights, Req::Required), + fname!("updateRight") => AssignIface::required().rights().public(), }, valencies: none!(), genesis: GenesisIface { @@ -128,7 +127,7 @@ pub fn fungible() -> Iface { fname!("issuedSupply") => GlobalIface::required(types.get("RGBContract.Amount")), }, assignments: tiny_bmap! { - fname!("assetOwner") => AssignIface::private(OwnedIface::Amount, Req::NoneOrMore), + fname!("assetOwner") => AssignIface::none_or_many().typed(types.get("RGBContract.Amount")), }, valencies: none!(), genesis: GenesisIface { @@ -232,6 +231,7 @@ pub fn reservable() -> Iface { */ pub fn fixed() -> Iface { + let types = StandardTypes::new(); Iface { version: VerNo::V1, name: tn!("FixedAsset"), @@ -241,7 +241,7 @@ pub fn fixed() -> Iface { metadata: none!(), global_state: none!(), assignments: tiny_bmap! { - fname!("assetOwner") => AssignIface::private(OwnedIface::Amount, Req::OneOrMore), + fname!("assetOwner") => AssignIface::one_or_many().typed(types.get("RGBContract.Amount")), }, valencies: none!(), genesis: GenesisIface { @@ -271,15 +271,13 @@ pub fn inflatable() -> Iface { developer: Identity::from(LNPBP_IDENTITY), timestamp: 1711405444, name: tn!("InflatableAsset"), - metadata: tiny_bmap! { - fname!("allowedInflation") => types.get("RGBContract.Amount"), - }, + metadata: none!(), global_state: tiny_bmap! { fname!("issuedSupply") => GlobalIface::one_or_many(types.get("RGBContract.Amount")), fname!("maxSupply") => GlobalIface::required(types.get("RGBContract.Amount")), }, assignments: tiny_bmap! { - fname!("inflationAllowance") => AssignIface::public(OwnedIface::Amount, Req::NoneOrMore), + fname!("inflationAllowance") => AssignIface::none_or_many().typed(types.get("RGBContract.Amount")).public(), }, valencies: none!(), genesis: GenesisIface { @@ -301,7 +299,7 @@ pub fn inflatable() -> Iface { fname!("issue") => TransitionIface { modifier: Modifier::Abstract, optional: false, - metadata: tiny_bset![fname!("allowedInflation")], + metadata: none!(), globals: tiny_bmap! { fname!("issuedSupply") => Occurrences::Once, }, @@ -347,7 +345,7 @@ pub fn burnable() -> Iface { fname!("burnedSupply") => GlobalIface::none_or_many(types.get("RGBContract.Amount")), }, assignments: tiny_bmap! { - fname!("burnRight") => AssignIface::public(OwnedIface::Rights, Req::OneOrMore), + fname!("burnRight") => AssignIface::one_or_many().rights().public(), }, valencies: none!(), genesis: GenesisIface { @@ -404,7 +402,7 @@ pub fn replaceable() -> Iface { fname!("replacedSupply") => GlobalIface::none_or_many(types.get("RGBContract.Amount")), }, assignments: tiny_bmap! { - fname!("replaceRight") => AssignIface::public(OwnedIface::Rights, Req::OneOrMore), + fname!("replaceRight") => AssignIface::one_or_many().rights().public(), }, valencies: none!(), genesis: GenesisIface { diff --git a/src/rgb20/info.rs b/src/rgb20/info.rs index 3cfef49..f68cd83 100644 --- a/src/rgb20/info.rs +++ b/src/rgb20/info.rs @@ -23,10 +23,10 @@ use std::fmt::{self, Display, Formatter, Write}; use chrono::{DateTime, Utc}; use rgbstd::info::ContractInfo; -use rgbstd::stl::Attachment; -use rgbstd::{Amount, Precision, XOutpoint, XWitnessId}; +use rgbstd::{XOutpoint, XWitnessId}; use crate::rgb20::Rgb20; +use crate::stl::{Amount, Attachment, Precision}; #[derive(Clone, PartialEq, Eq, Hash, Debug)] #[cfg_attr( diff --git a/src/rgb20/issuer.rs b/src/rgb20/issuer.rs index e916321..2a0503d 100644 --- a/src/rgb20/issuer.rs +++ b/src/rgb20/issuer.rs @@ -22,14 +22,14 @@ use std::str::FromStr; use bp::dbc::Method; +use rand::random; use rgbstd::containers::ValidContract; use rgbstd::interface::{BuilderError, ContractBuilder, IfaceClass, TxOutpoint}; -use rgbstd::invoice::{Amount, Precision}; -use rgbstd::stl::{AssetSpec, Attachment, ContractTerms, RicardianContract}; -use rgbstd::{AltLayer1, AssetTag, BlindingFactor, GenesisSeal, Identity}; +use rgbstd::{AltLayer1, GenesisSeal, Identity}; use strict_encoding::InvalidRString; use super::Rgb20; +use crate::stl::{Amount, AssetSpec, Attachment, ContractTerms, Precision, RicardianContract}; use crate::{IssuerWrapper, SchemaIssuer}; #[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Error)] @@ -69,7 +69,7 @@ impl PrimaryIssue { details: Option<&str>, precision: Precision, ) -> Result { - Self::testnet_int(issuer, by, ticker, name, details, precision, false) + Self::testnet_int(issuer, by, ticker, name, details, precision) } pub fn testnet>( @@ -79,23 +79,7 @@ impl PrimaryIssue { details: Option<&str>, precision: Precision, ) -> Result { - Self::testnet_int(C::issuer(), by, ticker, name, details, precision, false) - } - - pub fn testnet_det>( - by: &str, - ticker: &str, - name: &str, - details: Option<&str>, - precision: Precision, - asset_tag: AssetTag, - ) -> Result { - let mut me = Self::testnet_int(C::issuer(), by, ticker, name, details, precision, true)?; - me.builder = me - .builder - .add_asset_tag("assetOwner", asset_tag) - .expect("invalid RGB20 schema (assetOwner mismatch)"); - Ok(me) + Self::testnet_int(C::issuer(), by, ticker, name, details, precision) } fn testnet_int( @@ -105,7 +89,6 @@ impl PrimaryIssue { name: &str, details: Option<&str>, precision: Precision, - deterministic: bool, ) -> Result { let spec = AssetSpec::with(ticker, name, precision, details)?; let terms = ContractTerms { @@ -114,27 +97,16 @@ impl PrimaryIssue { }; let (schema, main_iface_impl, types, scripts, features) = issuer.into_split(); - let mut builder = match deterministic { - false => ContractBuilder::with( - Identity::from_str(by).expect("invalid issuer identity string"), - features.iface(), - schema, - main_iface_impl, - types, - scripts, - ), - true => ContractBuilder::deterministic( - Identity::from_str(by).expect("invalid issuer identity string"), - features.iface(), - schema, - main_iface_impl, - types, - scripts, - ), - }; - builder = builder - .add_global_state("spec", spec) - .expect("invalid RGB20 schema (token specification mismatch)"); + let builder = ContractBuilder::with( + Identity::from_str(by).expect("invalid issuer identity string"), + features.iface(), + schema, + main_iface_impl, + types, + scripts, + ) + .serialize_global_state("spec", &spec) + .expect("invalid RGB20 schema (token specification mismatch)"); Ok(Self { builder, @@ -163,27 +135,19 @@ impl PrimaryIssue { } pub fn add_inflation_metadata(mut self, amount: Amount) -> Result { - self.builder = self.builder.add_metadata("allowedInflation", amount)?; + self.builder = self + .builder + .serialize_metadata("allowedInflation", &amount)?; Ok(self) } pub fn allocate( - mut self, + self, method: Method, beneficiary: O, amount: impl Into, ) -> Result { - let amount = amount.into(); - let beneficiary = beneficiary.map_to_xchain(|outpoint| { - GenesisSeal::new_random(method, outpoint.txid, outpoint.vout) - }); - self.issued - .checked_add_assign(amount) - .ok_or(IssuerError::AmountOverflow)?; - self.builder = - self.builder - .add_fungible_state("assetOwner", beneficiary, amount.value())?; - Ok(self) + self.allocate_det(method, beneficiary, random(), amount) } pub fn allocate_all( @@ -204,7 +168,6 @@ impl PrimaryIssue { beneficiary: O, seal_blinding: u64, amount: impl Into, - amount_blinding: BlindingFactor, ) -> Result { let amount = amount.into(); let beneficiary = beneficiary.map_to_xchain(|outpoint| { @@ -213,52 +176,37 @@ impl PrimaryIssue { self.issued .checked_add_assign(amount) .ok_or(IssuerError::AmountOverflow)?; - self.builder = self.builder.add_fungible_state_det( - "assetOwner", - beneficiary, - amount, - amount_blinding, - )?; + self.builder = + self.builder + .serialize_owned_state("assetOwner", beneficiary, &amount, None)?; Ok(self) } pub fn allow_inflation( - mut self, + self, method: Method, controller: O, supply: impl Into, ) -> Result { - let supply = supply.into(); - let controller = controller.map_to_xchain(|outpoint| { - GenesisSeal::new_random(method, outpoint.txid, outpoint.vout) - }); - self = self.update_max_supply(supply)?; - self.builder = - self.builder - .add_fungible_state("inflationAllowance", controller, supply.value())?; - Ok(self) + self.allow_inflation_det(method, controller, random(), supply) } /// Add asset allocation in a deterministic way. pub fn allow_inflation_det( mut self, method: Method, - beneficiary: O, + controller: O, seal_blinding: u64, supply: impl Into, - supply_blinding: BlindingFactor, ) -> Result { let supply = supply.into(); - let beneficiary = beneficiary.map_to_xchain(|outpoint| { + let beneficiary = controller.map_to_xchain(|outpoint| { GenesisSeal::with_blinding(method, outpoint.txid, outpoint.vout, seal_blinding) }); self = self.update_max_supply(supply)?; - self.builder = self.builder.add_fungible_state_det( - "inflationAllowance", - beneficiary, - supply, - supply_blinding, - )?; + self.builder = + self.builder + .serialize_owned_state("inflationAllowance", beneficiary, &supply, None)?; Ok(self) } @@ -267,17 +215,7 @@ impl PrimaryIssue { Some(max) => max .checked_add_assign(supply) .ok_or(IssuerError::AmountOverflow)?, - None => { - let tag = self - .builder - .asset_tag("assetOwner") - .expect("asset tag must be already set"); - self.builder = self - .builder - .add_asset_tag("inflationAllowance", tag) - .expect("invalid RGB20 inflation allowance tag (inflation allowance mismatch)"); - self.inflation = Some(supply) - } + None => self.inflation = Some(supply), } Ok(self) } @@ -290,7 +228,7 @@ impl PrimaryIssue { let controller = controller.map_to_xchain(|outpoint| { GenesisSeal::new_random(method, outpoint.txid, outpoint.vout) }); - self.builder = self.builder.add_rights("burnRight", controller)?; + self.builder = self.builder.add_rights("burnRight", controller, None)?; Ok(self) } @@ -303,7 +241,7 @@ impl PrimaryIssue { let controller = controller.map_to_xchain(|outpoint| { GenesisSeal::with_blinding(method, outpoint.txid, outpoint.vout, seal_blinding) }); - self.builder = self.builder.add_rights("burnRight", controller)?; + self.builder = self.builder.add_rights("burnRight", controller, None)?; Ok(self) } @@ -315,7 +253,7 @@ impl PrimaryIssue { let controller = controller.map_to_xchain(|outpoint| { GenesisSeal::new_random(method, outpoint.txid, outpoint.vout) }); - self.builder = self.builder.add_rights("replaceRight", controller)?; + self.builder = self.builder.add_rights("replaceRight", controller, None)?; Ok(self) } @@ -328,17 +266,10 @@ impl PrimaryIssue { let controller = controller.map_to_xchain(|outpoint| { GenesisSeal::with_blinding(method, outpoint.txid, outpoint.vout, seal_blinding) }); - self.builder = self.builder.add_rights("replaceRight", controller)?; + self.builder = self.builder.add_rights("replaceRight", controller, None)?; Ok(self) } - // TODO: implement when bulletproofs are supported - /* - pub fn conceal_allocations(mut self) -> Self { - - } - */ - #[allow(clippy::result_large_err)] pub fn issue_contract(self) -> Result { Ok(self.pre_issue_contract()?.issue_contract()?) @@ -356,13 +287,13 @@ impl PrimaryIssue { .issued .checked_add(inflation) .ok_or(IssuerError::AmountOverflow)?; - self.builder = self.builder.add_global_state("maxSupply", max)?; + self.builder = self.builder.serialize_global_state("maxSupply", &max)?; } Ok(self .builder - .add_global_state("issuedSupply", self.issued)? - .add_global_state("terms", self.terms)?) + .serialize_global_state("issuedSupply", &self.issued)? + .serialize_global_state("terms", &self.terms)?) } - - // TODO: Add secondary issuance and other methods } + +// TODO: Add secondary issuer and other actors diff --git a/src/rgb20/mod.rs b/src/rgb20/mod.rs index 067a5a4..704ac1d 100644 --- a/src/rgb20/mod.rs +++ b/src/rgb20/mod.rs @@ -28,7 +28,6 @@ use amplify::confinement::Confined; use rgbstd::info::FeatureList; use rgbstd::interface::{Iface, IfaceClass, IfaceId}; use rgbstd::persistence::ContractStateRead; -use rgbstd::stl::rgb_contract_stl; use strict_types::TypeLib; use self::iface::{burnable, fixed, inflatable, replaceable, rgb20_base, rgb20_renamable}; @@ -41,6 +40,7 @@ use crate::rgb20::wrapper::{ RGB20_RENAMABLE_INFLATABLE_BURNABLE_IFACE_ID, RGB20_RENAMABLE_INFLATABLE_IFACE_ID, RGB20_REPLACABLE_IFACE_ID, }; +use crate::stl::rgb_contract_stl; pub const LIB_NAME_RGB20: &str = "RGB20"; diff --git a/src/rgb20/wrapper.rs b/src/rgb20/wrapper.rs index 09084f5..f18d8b3 100644 --- a/src/rgb20/wrapper.rs +++ b/src/rgb20/wrapper.rs @@ -20,21 +20,19 @@ // limitations under the License. use rgbstd::interface::{ - AssignmentsFilter, ContractIface, ContractOp, FungibleAllocation, IfaceClass, IfaceId, - IfaceWrapper, RightsAllocation, + AssignmentsFilter, ContractIface, ContractOp, IfaceClass, IfaceId, IfaceWrapper, Output, }; -use rgbstd::invoice::{Amount, Precision}; use rgbstd::persistence::ContractStateRead; -use rgbstd::stl::{AssetSpec, ContractTerms, Details}; -use rgbstd::{AssetTag, ContractId, SchemaId, WitnessInfo, XWitnessId}; +use rgbstd::{ContractId, SchemaId, WitnessInfo, XWitnessId}; use strict_encoding::InvalidRString; use super::{Inflation, PrimaryIssue, Rgb20, Rgb20Info}; +use crate::stl::{Amount, AssetSpec, ContractTerms, Details, Precision}; use crate::IssuerWrapper; pub const RGB20_FIXED_IFACE_ID: IfaceId = IfaceId::from_array([ - 0xfe, 0x25, 0x27, 0x3b, 0xd6, 0x8e, 0xd7, 0x18, 0x6a, 0x51, 0xde, 0xb5, 0x26, 0x6e, 0x52, 0xe7, - 0xec, 0x0c, 0xde, 0x78, 0x1b, 0xcb, 0x91, 0x95, 0x13, 0x29, 0x50, 0x65, 0x30, 0x0c, 0x60, 0x39, + 0x3a, 0xad, 0xab, 0x95, 0xf5, 0x46, 0x9b, 0xef, 0xab, 0x7a, 0x58, 0xaa, 0xd7, 0x42, 0x71, 0xba, + 0xd1, 0x41, 0x87, 0x32, 0x97, 0x42, 0x6c, 0x6d, 0x7d, 0x8c, 0xe0, 0x4d, 0xdd, 0x6a, 0x55, 0xf4, ]); pub const RGB20_RENAMABLE_IFACE_ID: IfaceId = IfaceId::from_array([ 0x99, 0xe1, 0xeb, 0xb5, 0x54, 0xd9, 0xeb, 0x10, 0x1d, 0x77, 0x4c, 0x2b, 0x8c, 0x3b, 0x6d, 0x2e, @@ -127,17 +125,6 @@ impl Rgb20Wrapper { PrimaryIssue::testnet::(issuer, ticker, name, details, precision) } - pub fn testnet_det>( - issuer: &str, - ticker: &str, - name: &str, - details: Option<&str>, - precision: Precision, - asset_tag: AssetTag, - ) -> Result { - PrimaryIssue::testnet_det::(issuer, ticker, name, details, precision, asset_tag) - } - pub fn features(&self) -> Rgb20 { let renaming = self .0 @@ -183,81 +170,76 @@ impl Rgb20Wrapper { } pub fn spec(&self) -> AssetSpec { - let strict_val = &self - .0 - .global("spec") + self.0 + .global_typed::("spec") .expect("RGB20 interface requires global state `spec`") .next() - .expect("RGB20 interface requires global state `spec` to have at least one item"); - AssetSpec::from_strict_val_unchecked(strict_val) + .expect("RGB20 interface requires global state `spec` to have at least one item") } pub fn balance(&self, filter: impl AssignmentsFilter) -> Amount { self.allocations(filter) - .map(|alloc| alloc.state) + .map(|output| output.state) .sum::() } pub fn allocations<'c>( &'c self, filter: impl AssignmentsFilter + 'c, - ) -> impl Iterator + 'c { + ) -> impl Iterator> + 'c { self.0 - .fungible("assetOwner", filter) + .outputs_typed("assetOwner", filter) .expect("RGB20 interface requires `assetOwner` state") } pub fn inflation_allowance_allocations<'c>( &'c self, filter: impl AssignmentsFilter + 'c, - ) -> impl Iterator + 'c { + ) -> impl Iterator> + 'c { self.0 - .fungible("inflationAllowance", filter) + .outputs_typed("inflationAllowance", filter) .expect("RGB20 interface requires `inflationAllowance` state") } pub fn update_right<'c>( &'c self, filter: impl AssignmentsFilter + 'c, - ) -> impl Iterator + 'c { + ) -> impl Iterator> + 'c { self.0 - .rights("updateRight", filter) + .outputs_typed("updateRight", filter) .expect("RGB20 interface requires `updateRight` state") } pub fn burn_epoch<'c>( &'c self, filter: impl AssignmentsFilter + 'c, - ) -> impl Iterator + 'c { + ) -> impl Iterator> + 'c { self.0 - .rights("burnEpoch", filter) + .outputs_typed("burnEpoch", filter) .expect("RGB20 interface requires `burnEpoch` state") } pub fn burn_right<'c>( &'c self, filter: impl AssignmentsFilter + 'c, - ) -> impl Iterator + 'c { + ) -> impl Iterator> + 'c { self.0 - .rights("burnRight", filter) + .outputs_typed("burnRight", filter) .expect("RGB20 interface requires `updateRight` state") } pub fn contract_terms(&self) -> ContractTerms { - let strict_val = &self - .0 - .global("terms") + self.0 + .global_typed::("terms") .expect("RGB20 interface requires global `terms`") .next() - .expect("RGB20 interface requires global state `terms` to have at least one item"); - ContractTerms::from_strict_val_unchecked(strict_val) + .expect("RGB20 interface requires global state `terms` to have at least one item") } pub fn total_issued_supply(&self) -> Amount { self.0 - .global("issuedSupply") + .global_typed::("issuedSupply") .expect("RGB20 interface requires global `issuedSupply`") - .map(|amount| Amount::from_strict_val_unchecked(&amount)) .sum() } @@ -265,31 +247,28 @@ impl Rgb20Wrapper { // default to the non-inflatable asset `issued supply` pub fn max_supply(&self) -> Amount { self.0 - .global("maxSupply") + .global_typed::("maxSupply") .unwrap_or_else(|_| { self.0 - .global("issuedSupply") + .global_typed("issuedSupply") .expect("RGB20 interface requires global `issuedSupply`") }) - .map(|amount| Amount::from_strict_val_unchecked(&amount)) .sum() } pub fn total_burned_supply(&self) -> Amount { self.0 - .global("burnedSupply") + .global_typed::("burnedSupply") .into_iter() .flatten() - .map(|amount| Amount::from_strict_val_unchecked(&amount)) .sum() } pub fn total_replaced_supply(&self) -> Amount { self.0 - .global("replacedSupply") + .global_typed::("replacedSupply") .into_iter() .flatten() - .map(|amount| Amount::from_strict_val_unchecked(&amount)) .sum() } diff --git a/src/rgb21/iface.rs b/src/rgb21/iface.rs index 7327e31..6ff155d 100644 --- a/src/rgb21/iface.rs +++ b/src/rgb21/iface.rs @@ -20,13 +20,12 @@ // limitations under the License. use rgbstd::interface::{ - AssignIface, GenesisIface, GlobalIface, Iface, IfaceClass, Modifier, OwnedIface, Req, - TransitionIface, VerNo, + AssignIface, GenesisIface, GlobalIface, Iface, IfaceClass, Modifier, TransitionIface, VerNo, }; -use rgbstd::stl::StandardTypes; use rgbstd::{Identity, Occurrences}; use super::Rgb21; +use crate::stl::StandardTypes; use crate::LNPBP_IDENTITY; pub fn nft() -> Iface { @@ -43,7 +42,7 @@ pub fn nft() -> Iface { fname!("attachmentTypes") => GlobalIface::none_or_many(types.get("RGB21.AttachmentType")), }, assignments: tiny_bmap! { - fname!("assetOwner") => AssignIface::private(OwnedIface::Data(types.get("RGBContract.Allocation")), Req::NoneOrMore), + fname!("assetOwner") => AssignIface::none_or_many().typed(types.get("RGBContract.Allocation")), }, valencies: none!(), genesis: GenesisIface { @@ -120,7 +119,7 @@ pub fn unique() -> Iface { fname!("attachmentTypes") => GlobalIface::required(types.get("RGB21.AttachmentType")), }, assignments: tiny_bmap! { - fname!("assetOwner") => AssignIface::private(OwnedIface::Data(types.get("RGBContract.Allocation")), Req::OneOrMore), + fname!("assetOwner") => AssignIface::one_or_many().typed(types.get("RGBContract.Allocation")), }, valencies: none!(), genesis: GenesisIface { @@ -157,7 +156,7 @@ pub fn limited() -> Iface { fname!("attachmentTypes") => GlobalIface::one_or_many(types.get("RGB21.AttachmentType")), }, assignments: tiny_bmap! { - fname!("assetOwner") => AssignIface::private(OwnedIface::Data(types.get("RGBContract.Allocation")), Req::OneOrMore), + fname!("assetOwner") => AssignIface::one_or_many().typed(types.get("RGBContract.Allocation")), }, valencies: none!(), genesis: GenesisIface { @@ -247,7 +246,7 @@ pub fn issuable() -> Iface { metadata: none!(), global_state: none!(), assignments: tiny_bmap! { - fname!("inflationAllowance") => AssignIface::public(OwnedIface::Data(types.get("RGB21.ItemsCount")), Req::OneOrMore), + fname!("inflationAllowance") => AssignIface::one_or_many().typed(types.get("RGB21.ItemsCount")).public(), }, valencies: none!(), genesis: GenesisIface { diff --git a/src/rgb21/mod.rs b/src/rgb21/mod.rs index 409440b..37e6e1f 100644 --- a/src/rgb21/mod.rs +++ b/src/rgb21/mod.rs @@ -31,8 +31,8 @@ use strict_types::TypeLib; use self::iface::{engravable, issuable, limited, nft, unique}; pub use self::types::{ - AttachmentName, AttachmentType, EmbeddedMedia, EngravingData, ItemsCount, TokenData, - LIB_ID_RGB21, LIB_NAME_RGB21, + AttachmentName, AttachmentType, EmbeddedMedia, EngravingData, ItemsCount, NftAllocation, + TokenData, LIB_ID_RGB21, LIB_NAME_RGB21, }; pub use self::wrapper::{Rgb21Wrapper, RGB21_IFACE_ID, RGB21_UNIQUE_IFACE_ID}; use crate::rgb20::iface::{named_asset, renameable}; diff --git a/src/rgb21/types.rs b/src/rgb21/types.rs index d2afd91..d43090a 100644 --- a/src/rgb21/types.rs +++ b/src/rgb21/types.rs @@ -28,13 +28,13 @@ use std::str::FromStr; use amplify::ascii::AsciiString; use amplify::confinement::{Confined, NonEmptyVec, SmallBlob}; -use rgbstd::stl::{Attachment, Details, MediaType, Name, ProofOfReserves, Ticker}; -use rgbstd::TokenIndex; use strict_encoding::stl::AsciiPrintable; use strict_encoding::{ InvalidRString, StrictDeserialize, StrictEncode, StrictSerialize, TypedWrite, }; -use strict_types::StrictVal; + +use crate::stl::{Attachment, Details, MediaType, Name, ProofOfReserves, Ticker}; +use crate::LIB_NAME_RGB_CONTRACT; pub const LIB_NAME_RGB21: &str = "RGB21"; /// Strict types id for the library providing data types for RGB21 interface. @@ -68,22 +68,8 @@ pub struct EngravingData { pub content: EmbeddedMedia, } -impl EngravingData { - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - let index = TokenIndex::from( - value - .unwrap_struct("index") - .unwrap_num() - .unwrap_uint::(), - ); - let content = EmbeddedMedia::from_strict_val_unchecked(value.unwrap_struct("content")); - - Self { - applied_to: index, - content, - } - } -} +impl StrictSerialize for EngravingData {} +impl StrictDeserialize for EngravingData {} #[derive(Clone, Eq, PartialEq, Hash, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] @@ -100,17 +86,6 @@ pub struct EmbeddedMedia { pub data: SmallBlob, } -impl EmbeddedMedia { - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - let ty = MediaType::from_strict_val_unchecked(value.unwrap_struct("type")); - let data = SmallBlob::from_iter_checked( - value.unwrap_struct("data").unwrap_bytes().iter().copied(), - ); - - Self { ty, data } - } -} - #[derive(Clone, Eq, PartialEq, Hash, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB21, dumb = { AttachmentType::with(0, "dumb") })] @@ -210,60 +185,208 @@ pub struct TokenData { impl StrictSerialize for TokenData {} impl StrictDeserialize for TokenData {} -impl TokenData { - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - let index = TokenIndex::from( - value - .unwrap_struct("index") - .unwrap_num() - .unwrap_uint::(), - ); - let ticker = value - .unwrap_struct("ticker") - .unwrap_option() - .map(|x| Ticker::from_str(&x.unwrap_string()).expect("invalid uda ticker")); - - let name = value - .unwrap_struct("name") - .unwrap_option() - .map(|x| Name::from_str(&x.unwrap_string()).expect("invalid uda name")); - - let details = value - .unwrap_struct("details") - .unwrap_option() - .map(|x| Details::from_str(&x.unwrap_string()).expect("invalid uda details")); - - let preview = value - .unwrap_struct("preview") - .unwrap_option() - .map(EmbeddedMedia::from_strict_val_unchecked); - let media = value - .unwrap_struct("media") - .unwrap_option() - .map(Attachment::from_strict_val_unchecked); - - let attachments = if let StrictVal::Map(list) = value.unwrap_struct("attachments") { - Confined::from_iter_checked( - list.iter() - .map(|(k, v)| (k.unwrap_uint(), Attachment::from_strict_val_unchecked(v))), - ) - } else { - Confined::default() - }; +#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] +#[display(inner)] +pub enum AllocationParseError { + #[display(doc_comments)] + /// invalid token index {0}. + InvalidIndex(String), + + #[display(doc_comments)] + /// invalid fraction {0}. + InvalidFraction(String), + + #[display(doc_comments)] + /// allocation must have format @. + WrongFormat, +} + +#[derive( + Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From +)] +#[wrapper(Display, FromStr, Add, Sub, Mul, Div, Rem)] +#[wrapper_mut(AddAssign, SubAssign, MulAssign, DivAssign, RemAssign)] +#[derive(StrictType, strict_encoding::StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct TokenIndex(u32); + +#[derive( + Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From +)] +#[wrapper(Display, FromStr, Add, Sub, Mul, Div, Rem)] +#[wrapper_mut(AddAssign, SubAssign, MulAssign, DivAssign, RemAssign)] +#[derive(StrictType, strict_encoding::StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct OwnedFraction(u64); + +impl OwnedFraction { + pub const ZERO: Self = OwnedFraction(0); + + pub fn value(self) -> u64 { self.0 } + + 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(); + } + + #[must_use] + pub fn checked_add(&self, other: impl Into) -> Option { + self.0.checked_add(other.into().0).map(Self) + } + #[must_use] + pub fn checked_sub(&self, other: impl Into) -> Option { + self.0.checked_sub(other.into().0).map(Self) + } + + #[must_use] + pub fn checked_add_assign(&mut self, other: impl Into) -> Option<()> { + *self = self.0.checked_add(other.into().0).map(Self)?; + Some(()) + } + #[must_use] + pub fn checked_sub_assign(&mut self, other: impl Into) -> Option<()> { + *self = self.0.checked_sub(other.into().0).map(Self)?; + Some(()) + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default, Display)] +#[display("{1}@{0}")] +#[derive(StrictType, strict_encoding::StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] +pub struct NftAllocation(TokenIndex, OwnedFraction); + +impl NftAllocation { + pub fn with(index: impl Into, fraction: impl Into) -> NftAllocation { + NftAllocation(index.into(), fraction.into()) + } + + pub fn token_index(self) -> TokenIndex { self.0 } + + pub fn fraction(self) -> OwnedFraction { self.1 } +} - let reserves = value - .unwrap_struct("reserves") - .unwrap_option() - .map(ProofOfReserves::from_strict_val_unchecked); - Self { - index, - ticker, - name, - details, - preview, - media, - attachments, - reserves, +impl StrictSerialize for NftAllocation {} +impl StrictDeserialize for NftAllocation {} + +impl FromStr for NftAllocation { + type Err = AllocationParseError; + + fn from_str(s: &str) -> Result { + if !s.contains('@') { + return Err(AllocationParseError::WrongFormat); } + + match s.split_once('@') { + Some((fraction, token_index)) => Ok(NftAllocation( + token_index + .parse() + .map_err(|_| AllocationParseError::InvalidIndex(token_index.to_owned()))?, + fraction + .parse() + .map_err(|_| AllocationParseError::InvalidFraction(fraction.to_lowercase()))?, + )), + None => Err(AllocationParseError::WrongFormat), + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn owned_fraction_from_str() { + let owned_fraction = match OwnedFraction::from_str("1") { + Ok(value) => value, + Err(_) => OwnedFraction::ZERO, + }; + + assert_eq!(owned_fraction.value(), 1); + assert_eq!(format!("{owned_fraction}"), "1"); + } + + #[test] + fn owned_fraction_add_assign() { + let mut owned_fraction = match OwnedFraction::from_str("1") { + Ok(value) => value, + Err(_) => OwnedFraction::ZERO, + }; + + let _ = owned_fraction.checked_add_assign(OwnedFraction::ZERO); + assert_eq!(owned_fraction.value(), 1); + assert_eq!(format!("{owned_fraction}"), "1"); + } + + #[test] + fn owned_fraction_add() { + let owned_fraction = match OwnedFraction::from_str("1") { + Ok(value) => value, + Err(_) => OwnedFraction::ZERO, + }; + + let owned = match owned_fraction.checked_add(OwnedFraction::ZERO) { + Some(value) => value, + None => OwnedFraction::ZERO, + }; + assert_eq!(owned.value(), 1); + assert_eq!(format!("{owned}"), "1"); + } + + #[test] + fn owned_fraction_sub() { + let owned_fraction = match OwnedFraction::from_str("1") { + Ok(value) => value, + Err(_) => OwnedFraction::ZERO, + }; + + let other_fraction = match OwnedFraction::from_str("1") { + Ok(value) => value, + Err(_) => OwnedFraction::ZERO, + }; + + let owned = match owned_fraction.checked_sub(other_fraction) { + Some(value) => value, + None => OwnedFraction::ZERO, + }; + assert_eq!(owned.value(), 0); + assert_eq!(format!("{owned}"), "0"); + } + + #[test] + fn owned_fraction_sub_assign() { + let mut owned_fraction = match OwnedFraction::from_str("1") { + Ok(value) => value, + Err(_) => OwnedFraction::ZERO, + }; + + let other_fraction = match OwnedFraction::from_str("1") { + Ok(value) => value, + Err(_) => OwnedFraction::ZERO, + }; + + let _ = owned_fraction.checked_sub_assign(other_fraction); + assert_eq!(owned_fraction.value(), 0); + assert_eq!(format!("{owned_fraction}"), "0"); } } diff --git a/src/rgb21/wrapper.rs b/src/rgb21/wrapper.rs index 9cfb14b..fdc2fd6 100644 --- a/src/rgb21/wrapper.rs +++ b/src/rgb21/wrapper.rs @@ -20,16 +20,19 @@ // limitations under the License. use rgbstd::interface::{ - AssignmentsFilter, ContractIface, ContractOp, DataAllocation, IfaceClass, IfaceId, IfaceWrapper, + AssignmentsFilter, ContractIface, ContractOp, IfaceClass, IfaceId, IfaceWrapper, Output, }; use rgbstd::persistence::ContractStateRead; -use rgbstd::stl::{bp_tx_stl, rgb_contract_stl, AssetSpec, ContractTerms}; +use rgbstd::stl::bp_tx_stl; use rgbstd::{Allocation, ContractId, SchemaId, WitnessInfo, XWitnessId}; use strict_types::stl::std_stl; use strict_types::{CompileError, LibBuilder, TypeLib}; -use super::{AttachmentType, EngravingData, ItemsCount, Rgb21, TokenData, LIB_NAME_RGB21}; +use super::{ + AttachmentType, EngravingData, ItemsCount, NftAllocation, Rgb21, TokenData, LIB_NAME_RGB21, +}; use crate::rgb20::Rgb20Info; +use crate::stl::{rgb_contract_stl, AssetSpec, ContractTerms}; pub const RGB21_UNIQUE_IFACE_ID: IfaceId = IfaceId::from_array([ 0xcd, 0xa8, 0x94, 0x87, 0x6e, 0xc5, 0xd9, 0xc6, 0x16, 0x7d, 0xc7, 0x45, 0x7c, 0xbe, 0x65, 0x05, @@ -87,48 +90,41 @@ impl IfaceWrapper for Rgb21Wrapper { impl Rgb21Wrapper { pub fn spec(&self) -> AssetSpec { - let strict_val = &self - .0 - .global("spec") + self.0 + .global_typed::("spec") .expect("RGB21 interface requires global `spec`") .next() - .expect("RGB21 interface requires global state `spec` to have at least one item"); - AssetSpec::from_strict_val_unchecked(strict_val) + .expect("RGB21 interface requires global state `spec` to have at least one item") } pub fn contract_terms(&self) -> ContractTerms { - let strict_val = &self - .0 - .global("terms") + self.0 + .global_typed::("terms") .expect("RGB21 interface requires global `terms`") .next() - .expect("RGB21 interface requires global state `terms` to have at least one item"); - ContractTerms::from_strict_val_unchecked(strict_val) + .expect("RGB21 interface requires global state `terms` to have at least one item") } pub fn token_data(&self) -> TokenData { - let strict_val = &self - .0 - .global("tokens") + self.0 + .global_typed::("tokens") .expect("RGB21 interface requires global `tokens`") .next() - .expect("RGB21 interface requires global state `tokens` to have at least one item"); - TokenData::from_strict_val_unchecked(strict_val) + .expect("RGB21 interface requires global state `tokens` to have at least one item") } pub fn engraving_data(&self) -> impl Iterator + '_ { self.0 - .global("engravings") + .global_typed::("engravings") .expect("RGB21 interface requires global state `engravings`") - .map(|strict_val| EngravingData::from_strict_val_unchecked(&strict_val)) } pub fn allocations<'c>( &'c self, filter: impl AssignmentsFilter + 'c, - ) -> impl Iterator + 'c { + ) -> impl Iterator> + 'c { self.0 - .data("assetOwner", filter) + .outputs_typed::("assetOwner", filter) .expect("RGB21 interface requires `assetOwner` state") } diff --git a/src/rgb25/iface.rs b/src/rgb25/iface.rs index 6261e55..c5bf71f 100644 --- a/src/rgb25/iface.rs +++ b/src/rgb25/iface.rs @@ -20,9 +20,9 @@ // limitations under the License. use rgbstd::interface::{GenesisIface, GlobalIface, Iface, Modifier, VerNo}; -use rgbstd::stl::StandardTypes; use rgbstd::{Identity, Occurrences}; +use crate::stl::StandardTypes; use crate::LNPBP_IDENTITY; pub fn named_contract() -> Iface { diff --git a/src/rgb25/info.rs b/src/rgb25/info.rs index b196704..dea7a25 100644 --- a/src/rgb25/info.rs +++ b/src/rgb25/info.rs @@ -22,10 +22,9 @@ use std::fmt::{self, Display, Formatter}; use rgbstd::info::ContractInfo; -use rgbstd::stl::Attachment; -use rgbstd::Precision; use crate::rgb25::Rgb25; +use crate::stl::{Attachment, Precision}; #[derive(Clone, PartialEq, Eq, Hash, Debug)] #[cfg_attr( diff --git a/src/rgb25/issuer.rs b/src/rgb25/issuer.rs index 46a5010..fec74e2 100644 --- a/src/rgb25/issuer.rs +++ b/src/rgb25/issuer.rs @@ -24,14 +24,12 @@ use std::str::FromStr; use bp::dbc::Method; use rgbstd::containers::ValidContract; use rgbstd::interface::{BuilderError, ContractBuilder, IfaceClass, TxOutpoint}; -use rgbstd::invoice::{Amount, Precision}; -use rgbstd::persistence::PersistedState; -use rgbstd::stl::{Attachment, ContractTerms, Details, Name, RicardianContract}; -use rgbstd::{AltLayer1, AssetTag, BlindingFactor, GenesisSeal, Identity}; +use rgbstd::{AltLayer1, GenesisSeal, Identity}; use strict_encoding::InvalidRString; use super::Rgb25; use crate::rgb20::IssuerError; +use crate::stl::{Amount, Attachment, ContractTerms, Details, Name, Precision, RicardianContract}; use crate::{IssuerWrapper, SchemaIssuer}; #[derive(Clone, Debug)] @@ -39,7 +37,6 @@ pub struct Issue { builder: ContractBuilder, issued: Amount, terms: ContractTerms, - deterministic: bool, } impl Issue { @@ -63,16 +60,15 @@ impl Issue { types, scripts, ) - .add_global_state("name", Name::try_from(name.to_owned())?) + .serialize_global_state("name", &Name::try_from(name.to_owned())?) .expect("invalid RGB25 schema (name mismatch)") - .add_global_state("precision", precision) + .serialize_global_state("precision", &precision) .expect("invalid RGB25 schema (precision mismatch)"); Ok(Self { builder, terms, issued: Amount::ZERO, - deterministic: false, }) } @@ -93,21 +89,6 @@ impl Issue { Self::testnet_int(issuer, by, name, precision) } - pub fn testnet_det>( - by: &str, - name: &str, - precision: Precision, - asset_tag: AssetTag, - ) -> Result { - let mut me = Self::testnet_int(C::issuer(), by, name, precision)?; - me.builder = me - .builder - .add_asset_tag("assetOwner", asset_tag) - .expect("invalid RGB25 schema (assetOwner mismatch)"); - me.deterministic = true; - Ok(me) - } - pub fn support_liquid(mut self) -> Self { self.builder = self .builder @@ -119,7 +100,7 @@ impl Issue { pub fn add_details(mut self, details: &str) -> Result { self.builder = self .builder - .add_global_state("details", Details::try_from(details.to_owned())?) + .serialize_global_state("details", &Details::try_from(details.to_owned())?) .expect("invalid RGB25 schema (details mismatch)"); Ok(self) } @@ -140,11 +121,6 @@ impl Issue { beneficiary: O, amount: Amount, ) -> Result { - debug_assert!( - !self.deterministic, - "for creating deterministic contracts please use allocate_det method" - ); - let beneficiary = beneficiary.map_to_xchain(|outpoint| { GenesisSeal::new_random(method, outpoint.txid, outpoint.vout) }); @@ -153,7 +129,7 @@ impl Issue { .ok_or(IssuerError::AmountOverflow)?; self.builder = self.builder - .add_fungible_state("assetOwner", beneficiary, amount.value())?; + .serialize_owned_state("assetOwner", beneficiary, &amount, None)?; Ok(self) } @@ -175,29 +151,16 @@ impl Issue { beneficiary: O, seal_blinding: u64, amount: Amount, - amount_blinding: BlindingFactor, ) -> Result { - debug_assert!( - self.deterministic, - "to add asset allocation in deterministic way the contract builder has to be created \ - using `*_det` constructor" - ); - - let tag = self - .builder - .asset_tag("assetOwner") - .expect("internal library error: asset tag is unassigned"); let beneficiary = beneficiary.map_to_xchain(|outpoint| { GenesisSeal::with_blinding(method, outpoint.txid, outpoint.vout, seal_blinding) }); self.issued .checked_add_assign(amount) .ok_or(IssuerError::AmountOverflow)?; - self.builder = self.builder.add_owned_state_det( - "assetOwner", - beneficiary, - PersistedState::Amount(amount, amount_blinding, tag), - )?; + self.builder = + self.builder + .serialize_owned_state("assetOwner", beneficiary, &amount, None)?; Ok(self) } @@ -221,11 +184,11 @@ impl Issue { #[allow(clippy::result_large_err)] fn pre_issue_contract(self) -> ContractBuilder { self.builder - .add_global_state("issuedSupply", self.issued) + .serialize_global_state("issuedSupply", &self.issued) .expect("invalid RGB25 schema (issued supply mismatch)") - .add_global_state("terms", self.terms) + .serialize_global_state("terms", &self.terms) .expect("invalid RGB25 schema (contract terms mismatch)") } - - // TODO: Add secondary issuance and other methods } + +// TODO: Add secondary issuance and other actors diff --git a/src/rgb25/mod.rs b/src/rgb25/mod.rs index acb60d9..6e8e859 100644 --- a/src/rgb25/mod.rs +++ b/src/rgb25/mod.rs @@ -30,13 +30,13 @@ pub use issuer::Issue; use rgbstd::info::FeatureList; use rgbstd::interface::{Iface, IfaceClass, IfaceId}; use rgbstd::persistence::ContractStateRead; -use rgbstd::stl::rgb_contract_stl; use strict_types::TypeLib; pub use wrapper::{Rgb25Wrapper, RGB25_IFACE_ID}; use crate::rgb20::iface::{burnable, fungible}; use crate::rgb25::iface::named_contract; use crate::rgb25::wrapper::RGB25_BASE_IFACE_ID; +use crate::stl::rgb_contract_stl; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)] #[cfg_attr( diff --git a/src/rgb25/wrapper.rs b/src/rgb25/wrapper.rs index 2bba10c..d9bc107 100644 --- a/src/rgb25/wrapper.rs +++ b/src/rgb25/wrapper.rs @@ -20,20 +20,19 @@ // limitations under the License. use rgbstd::interface::{ - AssignmentsFilter, ContractIface, FungibleAllocation, IfaceClass, IfaceId, IfaceWrapper, + AssignmentsFilter, ContractIface, IfaceClass, IfaceId, IfaceWrapper, Output, }; -use rgbstd::invoice::{Amount, Precision}; use rgbstd::persistence::ContractStateRead; -use rgbstd::stl::{ContractTerms, Details, Name}; -use rgbstd::{AssetTag, ContractId, SchemaId, WitnessInfo, XWitnessId}; +use rgbstd::{ContractId, SchemaId, WitnessInfo, XWitnessId}; use strict_encoding::InvalidRString; use super::{Issue, Rgb25, Rgb25Info}; +use crate::stl::{Amount, ContractTerms, Details, Name, Precision}; use crate::IssuerWrapper; pub const RGB25_BASE_IFACE_ID: IfaceId = IfaceId::from_array([ - 0x05, 0xd2, 0xa2, 0x30, 0x7b, 0x9b, 0x45, 0x94, 0xd8, 0xad, 0xb4, 0xb5, 0xdc, 0x6d, 0xf0, 0xb7, - 0xae, 0x2e, 0x21, 0xc8, 0x72, 0x3c, 0xc4, 0x05, 0xd0, 0xa9, 0xa6, 0xb1, 0x88, 0x1e, 0x32, 0x46, + 0xc4, 0x28, 0x29, 0x06, 0xeb, 0x65, 0x20, 0x6d, 0xfd, 0x36, 0x4f, 0x9a, 0xca, 0x79, 0x80, 0x12, + 0x63, 0x9d, 0xe6, 0xf7, 0x3d, 0xf7, 0x95, 0x86, 0xb5, 0x16, 0xc8, 0x7a, 0x3e, 0x7e, 0x16, 0x26, ]); pub const RGB25_IFACE_ID: IfaceId = IfaceId::from_array([ @@ -77,76 +76,58 @@ impl Rgb25Wrapper { Issue::testnet::(issuer, name, precision) } - pub fn testnet_det>( - issuer: &str, - name: &str, - precision: Precision, - asset_tag: AssetTag, - ) -> Result { - Issue::testnet_det::(issuer, name, precision, asset_tag) - } - pub fn name(&self) -> Name { - let strict_val = &self - .0 - .global("name") + self.0 + .global_typed::("name") .expect("RGB25 interface requires global `name`") .next() - .expect("RGB25 interface requires global state `name`"); - Name::from_strict_val_unchecked(strict_val) + .expect("RGB25 interface requires global state `name`") } pub fn details(&self) -> Option
{ self.0 - .global("details") + .global_typed::
("details") .expect("RGB25 interface requires global state `details`") .next() - .map(|strict_val| Details::from_strict_val_unchecked(&strict_val)) } pub fn precision(&self) -> Precision { - let strict_val = &self - .0 - .global("precision") + self.0 + .global_typed::("precision") .expect("RGB25 interface requires global state `precision`") .next() - .expect("RGB25 interface requires global state `precision` to have at least one item"); - Precision::from_strict_val_unchecked(strict_val) + .expect("RGB25 interface requires global state `precision` to have at least one item") } pub fn allocations<'c>( &'c self, filter: impl AssignmentsFilter + 'c, - ) -> impl Iterator + 'c { + ) -> impl Iterator> + 'c { self.0 - .fungible("assetOwner", filter) + .outputs_typed("assetOwner", filter) .expect("RGB25 interface requires `assetOwner` state") } pub fn total_issued_supply(&self) -> Amount { self.0 - .global("issuedSupply") + .global_typed::("issuedSupply") .expect("RGB25 interface requires global state `issuedSupply`") - .map(|strict_val| Amount::from_strict_val_unchecked(&strict_val)) .sum() } pub fn total_burned_supply(&self) -> Amount { self.0 - .global("burnedSupply") + .global_typed::("burnedSupply") .into_iter() .flatten() - .map(|strict_val| Amount::from_strict_val_unchecked(&strict_val)) .sum() } pub fn contract_terms(&self) -> ContractTerms { - let strict_val = &self - .0 - .global("terms") + self.0 + .global_typed::("terms") .expect("RGB25 interface requires global state `terms`") .next() - .expect("RGB25 interface requires global state `terms` to have at least one item"); - ContractTerms::from_strict_val_unchecked(strict_val) + .expect("RGB25 interface requires global state `terms` to have at least one item") } } diff --git a/src/stl/asset.rs b/src/stl/asset.rs new file mode 100644 index 0000000..8f919fa --- /dev/null +++ b/src/stl/asset.rs @@ -0,0 +1,239 @@ +// RGB interfaces by LNP/BP Standards Association +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2023-2024 by +// Dr Maxim Orlovsky +// +// Copyright (C) 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::iter::Sum; + +use bp::Sats; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +use strict_encoding::{StrictDeserialize, StrictSerialize}; + +use crate::LIB_NAME_RGB_CONTRACT; + +#[derive( + Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From +)] +#[wrapper(Add, Sub, Mul, Div, Rem, Display, FromStr)] +#[wrapper_mut(AddAssign, SubAssign, MulAssign, DivAssign, RemAssign)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct Amount( + #[from] + #[from(u32)] + #[from(u16)] + #[from(u8)] + #[from(Sats)] + u64, +); + +impl StrictSerialize for Amount {} +impl StrictDeserialize for Amount {} + +impl Amount { + pub const ZERO: Self = Amount(0); + + 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(); + } + + #[must_use] + pub fn checked_add(&self, other: impl Into) -> Option { + self.0.checked_add(other.into().0).map(Self) + } + #[must_use] + pub fn checked_sub(&self, other: impl Into) -> Option { + self.0.checked_sub(other.into().0).map(Self) + } + + #[must_use] + pub fn checked_add_assign(&mut self, other: impl Into) -> Option<()> { + *self = self.0.checked_add(other.into().0).map(Self)?; + Some(()) + } + #[must_use] + pub fn checked_sub_assign(&mut self, other: impl Into) -> Option<()> { + *self = self.0.checked_sub(other.into().0).map(Self)?; + Some(()) + } +} + +impl Sum for Amount { + 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, |sum, value| sum.saturating_add(value)) + } +} + +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)] +#[repr(u8)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT, tags = repr, into_u8, try_from_u8)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub enum Precision { + Indivisible = 0, + Deci = 1, + Centi = 2, + Milli = 3, + DeciMilli = 4, + CentiMilli = 5, + Micro = 6, + DeciMicro = 7, + #[default] + CentiMicro = 8, + Nano = 9, + DeciNano = 10, + CentiNano = 11, + Pico = 12, + DeciPico = 13, + CentiPico = 14, + Femto = 15, + DeciFemto = 16, + CentiFemto = 17, + Atto = 18, +} + +impl StrictSerialize for Precision {} +impl StrictDeserialize for Precision {} + +impl Precision { + pub const fn decimals(self) -> u8 { self as u8 } + + 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() + } +} + +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 } +} diff --git a/src/stl/chain.rs b/src/stl/chain.rs new file mode 100644 index 0000000..29aed06 --- /dev/null +++ b/src/stl/chain.rs @@ -0,0 +1,43 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2024 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use amplify::confinement::SmallBlob; +use bp::Outpoint; +use strict_encoding::{StrictDeserialize, StrictSerialize}; + +use crate::LIB_NAME_RGB_CONTRACT; + +#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT, dumb = ProofOfReserves::new(strict_dumb!(), strict_dumb!()))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] +pub struct ProofOfReserves { + pub utxo: Outpoint, + pub proof: SmallBlob, +} +impl StrictSerialize for ProofOfReserves {} +impl StrictDeserialize for ProofOfReserves {} + +impl ProofOfReserves { + pub fn new(utxo: Outpoint, proof: SmallBlob) -> ProofOfReserves { + ProofOfReserves { utxo, proof } + } +} diff --git a/src/stl/mime.rs b/src/stl/mime.rs new file mode 100644 index 0000000..6642181 --- /dev/null +++ b/src/stl/mime.rs @@ -0,0 +1,190 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2024 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(unused_braces)] + +use std::fmt::{self, Debug}; +use std::str::FromStr; + +use strict_encoding::stl::AlphaSmall; +use strict_encoding::{ + RString, RestrictedCharSet, StrictDeserialize, StrictDumb, StrictEncode, StrictSerialize, +}; + +use super::LIB_NAME_RGB_CONTRACT; + +#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug, Hash)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] +pub struct MediaType { + #[strict_type(rename = "type")] + #[cfg_attr(feature = "serde", serde(rename = "type"))] + pub ty: MediaRegName, + pub subtype: Option, + pub charset: Option, +} +impl StrictDumb for MediaType { + fn strict_dumb() -> Self { MediaType::with("text/plain") } +} +impl StrictSerialize for MediaType {} +impl StrictDeserialize for MediaType {} + +impl MediaType { + /// # Safety + /// + /// Panics is the provided string is an invalid type specifier. + pub fn with(s: &'static str) -> Self { + let (ty, subty) = s.split_once('/').expect("invalid static media type string"); + MediaType { + ty: MediaRegName::from(ty), + subtype: if subty == "*" { None } else { Some(MediaRegName::from(subty)) }, + charset: None, + } + } +} + +impl fmt::Display for MediaType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}/{}", + self.ty, + if let Some(subty) = &self.subtype { subty.to_string() } else { s!("*") } + ) + } +} + +#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] +#[wrapper(Deref, Display, FromStr)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT, dumb = { MediaRegName::from("dumb") })] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct MediaRegName(RString); + +impl_ident_type!(MediaRegName); +impl_ident_subtype!(MediaRegName); + +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] +#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT, tags = repr, into_u8, try_from_u8)] +#[display(inner)] +#[repr(u8)] +#[allow(non_camel_case_types)] +pub enum MimeChar { + #[display("!")] + Excl = b'!', + #[display("#")] + Hash = b'#', + #[display("$")] + Dollar = b'$', + #[display("&")] + Amp = b'&', + #[display("+")] + Plus = b'+', + #[display("-")] + Dash = b'-', + #[display(".")] + Dot = b'.', + #[display("0")] + Zero = b'0', + #[display("1")] + One = b'1', + #[display("2")] + Two = b'2', + #[display("3")] + Three = b'3', + #[display("4")] + Four = b'4', + #[display("5")] + Five = b'5', + #[display("6")] + Six = b'6', + #[display("7")] + Seven = b'7', + #[display("8")] + Eight = b'8', + #[display("9")] + Nine = b'9', + #[display("^")] + Caret = b'^', + #[display("_")] + Lodash = b'_', + #[strict_type(dumb)] + #[display("a")] + a = b'a', + #[display("b")] + b = b'b', + #[display("c")] + c = b'c', + #[display("d")] + d = b'd', + #[display("e")] + e = b'e', + #[display("f")] + f = b'f', + #[display("g")] + g = b'g', + #[display("h")] + h = b'h', + #[display("i")] + i = b'i', + #[display("j")] + j = b'j', + #[display("k")] + k = b'k', + #[display("l")] + l = b'l', + #[display("m")] + m = b'm', + #[display("n")] + n = b'n', + #[display("o")] + o = b'o', + #[display("p")] + p = b'p', + #[display("q")] + q = b'q', + #[display("r")] + r = b'r', + #[display("s")] + s = b's', + #[display("t")] + t = b't', + #[display("u")] + u = b'u', + #[display("v")] + v = b'v', + #[display("w")] + w = b'w', + #[display("x")] + x = b'x', + #[display("y")] + y = b'y', + #[display("z")] + z = b'z', +} + +impl RestrictedCharSet for MimeChar {} diff --git a/src/stl/mod.rs b/src/stl/mod.rs new file mode 100644 index 0000000..d34f208 --- /dev/null +++ b/src/stl/mod.rs @@ -0,0 +1,38 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2024 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod specs; +#[allow(clippy::module_inception)] +mod stl; +mod mime; +mod chain; +mod asset; + +pub use asset::{Amount, Precision}; +pub use chain::ProofOfReserves; +pub use mime::{MediaRegName, MediaType}; +pub use specs::{ + Article, AssetSpec, Attachment, BurnMeta, ContractSpec, ContractTerms, Details, IssueMeta, + Name, RicardianContract, Ticker, +}; +pub use stl::{rgb_contract_stl, StandardTypes, LIB_ID_RGB_CONTRACT}; + +pub const LIB_NAME_RGB_CONTRACT: &str = "RGBContract"; diff --git a/src/stl/specs.rs b/src/stl/specs.rs new file mode 100644 index 0000000..9fe5fac --- /dev/null +++ b/src/stl/specs.rs @@ -0,0 +1,330 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2024 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(unused_braces)] // caused by rustc unable to understand strict_dumb + +use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; +use std::str::FromStr; + +use amplify::confinement::{Confined, NonEmptyString, SmallOrdSet, SmallString, U8}; +use amplify::Bytes32; +use strict_encoding::stl::{Alpha, AlphaNum, AsciiPrintable}; +use strict_encoding::{ + InvalidRString, RString, StrictDeserialize, StrictDumb, StrictEncode, StrictSerialize, + StrictType, +}; + +use super::{MediaType, Precision, ProofOfReserves, LIB_NAME_RGB_CONTRACT}; + +#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct BurnMeta { + pub burn_proofs: SmallOrdSet, +} +impl StrictSerialize for BurnMeta {} +impl StrictDeserialize for BurnMeta {} + +#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct IssueMeta { + pub reserves: SmallOrdSet, +} +impl StrictSerialize for IssueMeta {} +impl StrictDeserialize for IssueMeta {} + +#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] +#[wrapper(Deref, Display, FromStr)] +#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT, dumb = { Article::from("DUMB") })] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct Article(RString); + +impl_ident_type!(Article); +impl_ident_subtype!(Article); + +#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, From)] +#[wrapper(Deref, Display, FromStr)] +#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT, dumb = { Ticker::from("DUMB") })] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct Ticker(RString); + +impl PartialEq for Ticker { + fn eq(&self, other: &Self) -> bool { + self.as_str() + .to_uppercase() + .eq(&other.as_str().to_uppercase()) + } +} + +impl Hash for Ticker { + fn hash(&self, state: &mut H) { self.as_str().to_uppercase().hash(state) } +} + +impl_ident_type!(Ticker); +impl_ident_subtype!(Ticker); + +#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] +#[wrapper(Deref, Display, FromStr)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct Name(RString); + +impl StrictSerialize for Name {} +impl StrictDeserialize for Name {} + +impl_ident_type!(Name); +impl_ident_subtype!(Name); + +#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] +#[wrapper(Deref, Display)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct Details(NonEmptyString); +impl StrictSerialize for Details {} +impl StrictDeserialize for Details {} + +impl AsRef for Details { + #[inline] + fn as_ref(&self) -> &str { self.0.as_str() } +} + +impl StrictDumb for Details { + fn strict_dumb() -> Self { + Self(Confined::try_from(s!("Dumb long description which is stupid and so on...")).unwrap()) + } +} + +impl FromStr for Details { + type Err = InvalidRString; + + fn from_str(s: &str) -> Result { + let s = Confined::try_from_iter(s.chars())?; + Ok(Self(s)) + } +} + +impl From<&'static str> for Details { + fn from(s: &'static str) -> Self { Self::from_str(s).expect("invalid details") } +} + +impl TryFrom for Details { + type Error = InvalidRString; + + fn try_from(name: String) -> Result { + let s = Confined::try_from(name)?; + Ok(Self(s)) + } +} + +impl Debug for Details { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_tuple("ContractDetails") + .field(&self.as_str()) + .finish() + } +} + +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct AssetSpec { + pub ticker: Ticker, + pub name: Name, + pub details: Option
, + pub precision: Precision, +} +impl StrictSerialize for AssetSpec {} +impl StrictDeserialize for AssetSpec {} + +impl AssetSpec { + pub fn new(ticker: &'static str, name: &'static str, precision: Precision) -> AssetSpec { + AssetSpec { + ticker: Ticker::from(ticker), + name: Name::from(name), + details: None, + precision, + } + } + + pub fn with( + ticker: &str, + name: &str, + precision: Precision, + details: Option<&str>, + ) -> Result { + Ok(AssetSpec { + ticker: Ticker::try_from(ticker.to_owned())?, + name: Name::try_from(name.to_owned())?, + details: details.map(Details::from_str).transpose()?, + precision, + }) + } + + pub fn ticker(&self) -> &str { self.ticker.as_str() } + + pub fn name(&self) -> &str { self.name.as_str() } + + pub fn details(&self) -> Option<&str> { self.details.as_ref().map(|d| d.as_str()) } +} + +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct ContractSpec { + pub article: Option
, + pub name: Name, + pub details: Option
, + pub precision: Precision, +} +impl StrictSerialize for ContractSpec {} +impl StrictDeserialize for ContractSpec {} + +impl ContractSpec { + pub fn new(name: &'static str, precision: Precision) -> ContractSpec { + ContractSpec { + article: None, + name: Name::from(name), + details: None, + precision, + } + } + + pub fn with( + article: &str, + name: &str, + precision: Precision, + details: Option<&str>, + ) -> Result { + Ok(ContractSpec { + article: Some(Article::try_from(article.to_owned())?), + name: Name::try_from(name.to_owned())?, + details: details.map(Details::from_str).transpose()?, + precision, + }) + } + + pub fn article(&self) -> Option<&str> { self.article.as_ref().map(|a| a.as_str()) } + + pub fn name(&self) -> &str { self.name.as_str() } + + pub fn details(&self) -> Option<&str> { self.details.as_ref().map(|d| d.as_str()) } +} + +#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Default)] +#[display(inner)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct RicardianContract(SmallString); +impl StrictSerialize for RicardianContract {} +impl StrictDeserialize for RicardianContract {} + +impl AsRef for RicardianContract { + #[inline] + fn as_ref(&self) -> &str { self.0.as_str() } +} + +impl FromStr for RicardianContract { + type Err = InvalidRString; + + fn from_str(s: &str) -> Result { + let s = Confined::try_from_iter(s.chars())?; + Ok(Self(s)) + } +} + +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct Attachment { + #[strict_type(rename = "type")] + #[cfg_attr(feature = "serde", serde(rename = "type"))] + pub ty: MediaType, + pub digest: Bytes32, +} +impl StrictSerialize for Attachment {} +impl StrictDeserialize for Attachment {} + +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct ContractTerms { + pub text: RicardianContract, + pub media: Option, +} +impl StrictSerialize for ContractTerms {} +impl StrictDeserialize for ContractTerms {} diff --git a/src/stl/stl.rs b/src/stl/stl.rs new file mode 100644 index 0000000..1df7aa7 --- /dev/null +++ b/src/stl/stl.rs @@ -0,0 +1,106 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2024 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use bp::bc::stl::bp_tx_stl; +use strict_types::stl::std_stl; +use strict_types::typesys::SystemBuilder; +use strict_types::{typesys, CompileError, LibBuilder, SemId, SymbolicSys, TypeLib, TypeSystem}; + +use super::{ + Amount, AssetSpec, BurnMeta, ContractSpec, ContractTerms, IssueMeta, MediaType, + LIB_NAME_RGB_CONTRACT, +}; +use crate::stl::ProofOfReserves; + +/// Strict types id for the library providing standard data types which may be +/// used in RGB smart contracts. +pub const LIB_ID_RGB_CONTRACT: &str = + "stl:X4nmhvtX-V2JgDnw-aZGsWe9-jvPZ3FT-px99uMI-EaiAYx8#paint-fruit-first"; + +fn _rgb_contract_stl() -> Result { + LibBuilder::new(libname!(LIB_NAME_RGB_CONTRACT), tiny_bset! { + std_stl().to_dependency(), + bp_tx_stl().to_dependency() + }) + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .compile() +} + +/// Generates strict type library providing standard data types which may be +/// used in RGB smart contracts. +pub fn rgb_contract_stl() -> TypeLib { + _rgb_contract_stl().expect("invalid strict type RGBContract library") +} + +#[derive(Debug)] +pub struct StandardTypes(SymbolicSys); + +impl Default for StandardTypes { + fn default() -> Self { StandardTypes::new() } +} + +impl StandardTypes { + pub fn new() -> Self { + Self::try_with([std_stl(), bp_tx_stl(), rgb_contract_stl()]) + .expect("error in standard RGBContract type system") + } + + pub fn with(lib: TypeLib) -> Self { + Self::try_with([std_stl(), bp_tx_stl(), rgb_contract_stl(), lib]) + .expect("error in standard RGBContract type system") + } + + #[allow(clippy::result_large_err)] + fn try_with(libs: impl IntoIterator) -> Result> { + let mut builder = SystemBuilder::new(); + for lib in libs.into_iter() { + builder = builder.import(lib).map_err(|e| vec![e])?; + } + let sys = builder.finalize()?; + Ok(Self(sys)) + } + + pub fn type_system(&self) -> TypeSystem { self.0.as_types().clone() } + + pub fn get(&self, name: &'static str) -> SemId { + *self.0.resolve(name).unwrap_or_else(|| { + panic!("type '{name}' is absent in standard RGBContract type library") + }) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn contract_lib_id() { + let lib = rgb_contract_stl(); + assert_eq!(lib.id().to_string(), LIB_ID_RGB_CONTRACT); + } +}