diff --git a/.gitignore b/.gitignore index ea8c4bf7..81cf4658 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/.vscode diff --git a/Cargo.lock b/Cargo.lock index d8281753..d5f412ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -28,9 +34,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "base64" @@ -40,9 +46,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "base64" -version = "0.21.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" @@ -50,17 +56,29 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" -version = "3.11.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cc" -version = "1.0.73" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -70,15 +88,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.22" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ + "android-tzdata", "iana-time-zone", - "num-integer", "num-traits", "serde", - "winapi", + "windows-targets", ] [[package]] @@ -112,7 +130,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.79", ] [[package]] @@ -122,20 +140,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" [[package]] -name = "codespan-reporting" -version = "0.11.1" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "core-foundation-sys" -version = "0.8.3" +name = "cpufeatures" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] [[package]] name = "crate-git-revision" @@ -149,47 +166,13 @@ dependencies = [ ] [[package]] -name = "cxx" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f39818dcfc97d45b03953c1292efc4e80954e1583c4aa770bac1383e2310a4" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.78" +name = "crypto-common" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e580d70777c116df50c390d1211993f62d40302881e54d4b79727acb83d0199" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 1.0.98", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56a46460b88d1cec95112c8c363f0e2c39afdb237f60583b0b36343bf627ea9c" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747b608fecf06b0d72d440f27acc99288207324b793be2c17991839f3d4995ea" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", + "generic-array", + "typenum", ] [[package]] @@ -213,7 +196,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.15", + "syn 2.0.79", ] [[package]] @@ -224,7 +207,7 @@ checksum = "7bfb82b62b1b8a2a9808fb4caf844ede819a76cfc23b2827d7f94eefb49551eb" dependencies = [ "darling_core", "quote", - "syn 2.0.15", + "syn 2.0.79", ] [[package]] @@ -233,6 +216,16 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "derive_arbitrary" version = "1.1.3" @@ -244,12 +237,28 @@ dependencies = [ "syn 1.0.98", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dyn-clone" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "escape-bytes" version = "0.1.1" @@ -262,12 +271,28 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "heck" version = "0.4.0" @@ -285,26 +310,25 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.51" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows-core", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fde6edd6cef363e9359ed3c98ba64590ba9eecba2293eb5a723ab32aee8926aa" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -315,12 +339,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.0", "serde", ] @@ -332,85 +367,72 @@ checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.135" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] -name = "link-cplusplus" -version = "1.0.7" +name = "log" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" -dependencies = [ - "cc", -] +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] -name = "log" -version = "0.4.17" +name = "memchr" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] -name = "num-integer" -version = "0.1.45" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - [[package]] name = "once_cell" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -445,30 +467,24 @@ dependencies = [ "syn 1.0.98", ] -[[package]] -name = "scratch" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" - [[package]] name = "serde" -version = "1.0.160" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.79", ] [[package]] @@ -484,26 +500,29 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_with" -version = "3.0.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513" +checksum = "9720086b3357bcb44fce40117d769a4d068c70ecfa190850a980a71755f66fcc" dependencies = [ - "base64 0.21.0", + "base64 0.22.1", "chrono", "hex", - "indexmap", + "indexmap 1.9.3", + "indexmap 2.6.0", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -511,16 +530,33 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.0.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070" +checksum = "5f1abbfe725f27678f4663bcacb75a83e829fd464c25d78dd038a3a29e307cec" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.79", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "stellar-strkey" version = "0.0.9" @@ -546,6 +582,7 @@ dependencies = [ "serde", "serde_json", "serde_with", + "sha2", "stellar-strkey", "thiserror", ] @@ -569,24 +606,15 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - [[package]] name = "thiserror" version = "1.0.37" @@ -609,16 +637,41 @@ dependencies = [ [[package]] name = "time" -version = "0.3.15" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ + "deranged", "itoa", - "libc", - "num_threads", + "num-conv", + "powerfmt", "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.1" @@ -626,41 +679,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" [[package]] -name = "unicode-width" -version = "0.1.10" +name = "version_check" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.98", + "syn 2.0.79", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -668,50 +722,92 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] -name = "winapi" -version = "0.3.9" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows-targets", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] [[package]] -name = "winapi-util" -version = "0.1.5" +name = "windows_aarch64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index e49d37b0..81b86de7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ doctest = false crate-git-revision = "0.0.6" [dependencies] +sha2 = { version = "0.10.7", optional = true } stellar-strkey = { version = "0.0.9", optional = true } base64 = { version = "0.13.0", optional = true } serde = { version = "1.0.139", features = ["derive"], optional = true } @@ -45,12 +46,29 @@ next = [] base64 = ["std", "dep:base64"] serde = ["alloc", "dep:serde", "dep:serde_with", "hex/serde"] serde_json = ["std", "serde", "dep:serde_json"] +# serde_wasm_bindgen = [ +# "std", +# "serde", +# "dep:serde-wasm-bindgen", +# "dep:wasm-bindgen", +# ] schemars = ["alloc", "serde", "serde_json", "dep:schemars"] arbitrary = ["std", "dep:arbitrary"] hex = [] # Features for the CLI. -cli = ["std", "curr", "next", "base64", "serde", "serde_json", "schemars", "dep:clap", "dep:thiserror"] +cli = [ + "std", + "curr", + "next", + "base64", + "serde", + "serde_json", + "schemars", + "dep:clap", + "dep:thiserror", + "sha2", +] [package.metadata.docs.rs] all-features = true diff --git a/Makefile b/Makefile index a7ebf306..e709287f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ export RUSTFLAGS=-Dwarnings -Dclippy::all -Dclippy::pedantic -CARGO_HACK_ARGS=--feature-powerset --exclude-features default --group-features base64,serde,arbitrary,hex +CARGO_HACK_ARGS=--feature-powerset --exclude-features default --group-features base64,serde,arbitrary,hex,sha2 CARGO_DOC_ARGS?=--open diff --git a/src/curr/account_conversions.rs b/src/curr/account_conversions.rs index 19378d2b..9655ae75 100644 --- a/src/curr/account_conversions.rs +++ b/src/curr/account_conversions.rs @@ -1,25 +1,322 @@ -use super::{AccountId, MuxedAccount, PublicKey}; +use super::{ + AccountId, Hash, MuxedAccount, MuxedAccountMed25519, PublicKey, ScAddress, ScVal, Uint256, +}; -impl From for MuxedAccount { - fn from(account_id: AccountId) -> Self { - account_id.0.into() +#[cfg(feature = "alloc")] +mod strkey { + use super::super::Error; + use super::*; + impl From for PublicKey { + fn from(k: stellar_strkey::ed25519::PublicKey) -> Self { + PublicKey::PublicKeyTypeEd25519(k.0.into()) + } + } + impl From<&stellar_strkey::ed25519::PublicKey> for PublicKey { + fn from(k: &stellar_strkey::ed25519::PublicKey) -> Self { + PublicKey::PublicKeyTypeEd25519(k.0.into()) + } + } + + impl From for AccountId { + fn from(k: stellar_strkey::ed25519::PublicKey) -> Self { + AccountId(k.into()) + } + } + impl From<&stellar_strkey::ed25519::PublicKey> for AccountId { + fn from(k: &stellar_strkey::ed25519::PublicKey) -> Self { + AccountId(k.into()) + } + } + + impl From for ScAddress { + fn from(t: stellar_strkey::ed25519::PublicKey) -> Self { + ScAddress::Account(t.into()) + } + } + impl From<&stellar_strkey::ed25519::PublicKey> for ScAddress { + fn from(t: &stellar_strkey::ed25519::PublicKey) -> Self { + ScAddress::Account(t.into()) + } + } + + impl From for ScVal { + fn from(k: stellar_strkey::ed25519::PublicKey) -> Self { + ScVal::Address(k.into()) + } + } + impl From<&stellar_strkey::ed25519::PublicKey> for ScVal { + fn from(k: &stellar_strkey::ed25519::PublicKey) -> Self { + ScVal::Address(k.into()) + } + } + + impl From for PublicKey { + fn from(k: stellar_strkey::ed25519::MuxedAccount) -> Self { + PublicKey::PublicKeyTypeEd25519(k.ed25519.into()) + } + } + impl From<&stellar_strkey::ed25519::MuxedAccount> for PublicKey { + fn from( + stellar_strkey::ed25519::MuxedAccount{ ed25519, .. }: &stellar_strkey::ed25519::MuxedAccount, + ) -> Self { + PublicKey::PublicKeyTypeEd25519(ed25519.into()) + } + } + + impl From for AccountId { + fn from(k: stellar_strkey::ed25519::MuxedAccount) -> Self { + AccountId(k.into()) + } + } + impl From<&stellar_strkey::ed25519::MuxedAccount> for AccountId { + fn from(k: &stellar_strkey::ed25519::MuxedAccount) -> Self { + AccountId(k.into()) + } + } + + impl From for ScAddress { + fn from(t: stellar_strkey::ed25519::MuxedAccount) -> Self { + ScAddress::Account(t.into()) + } + } + impl From<&stellar_strkey::ed25519::MuxedAccount> for ScAddress { + fn from(t: &stellar_strkey::ed25519::MuxedAccount) -> Self { + ScAddress::Account(t.into()) + } + } + + impl From for ScVal { + fn from(k: stellar_strkey::ed25519::MuxedAccount) -> Self { + ScVal::Address(k.into()) + } + } + impl From<&stellar_strkey::ed25519::MuxedAccount> for ScVal { + fn from(k: &stellar_strkey::ed25519::MuxedAccount) -> Self { + ScVal::Address(k.into()) + } + } + + impl TryFrom<&stellar_strkey::Strkey> for ScAddress { + type Error = Error; + fn try_from(strkey: &stellar_strkey::Strkey) -> Result { + match strkey { + stellar_strkey::Strkey::PublicKeyEd25519(k) => Ok(ScAddress::Account(k.into())), + stellar_strkey::Strkey::MuxedAccountEd25519(m) => Ok(ScAddress::Account(m.into())), + stellar_strkey::Strkey::Contract(k) => Ok(ScAddress::Contract(k.into())), + _ => Err(Error::Invalid), + } + } + } + + impl From for stellar_strkey::ed25519::PublicKey { + fn from(k: PublicKey) -> Self { + (&k).into() + } + } + impl From<&PublicKey> for stellar_strkey::ed25519::PublicKey { + fn from(k: &PublicKey) -> Self { + match k { + PublicKey::PublicKeyTypeEd25519(k) => stellar_strkey::ed25519::PublicKey(k.into()), + } + } + } + impl From for stellar_strkey::Strkey { + fn from(sc_address: ScAddress) -> Self { + match sc_address { + ScAddress::Account(account_id) => { + stellar_strkey::Strkey::PublicKeyEd25519(account_id.into()) + } + ScAddress::Contract(contract) => stellar_strkey::Strkey::Contract(contract.into()), + } + } + } + impl From<&ScAddress> for stellar_strkey::Strkey { + fn from(sc_address: &ScAddress) -> Self { + match sc_address { + ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(k)))) => { + stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(*k)) + } + ScAddress::Contract(Hash(h)) => { + stellar_strkey::Strkey::Contract(stellar_strkey::Contract(*h)) + } + } + } + } + impl From for stellar_strkey::ed25519::PublicKey { + fn from(value: AccountId) -> Self { + match value { + AccountId(key) => key.into(), + } + } + } + impl From<&AccountId> for stellar_strkey::ed25519::PublicKey { + fn from(value: &AccountId) -> Self { + match value { + AccountId(key) => key.into(), + } + } } } impl From for MuxedAccount { fn from(public_key: PublicKey) -> Self { + (&public_key).into() + } +} +impl From<&PublicKey> for MuxedAccount { + fn from(public_key: &PublicKey) -> Self { + match public_key { + PublicKey::PublicKeyTypeEd25519(k) => MuxedAccount::Ed25519(k.into()), + } + } +} + +impl From<&PublicKey> for PublicKey { + fn from(public_key: &PublicKey) -> Self { match public_key { - PublicKey::PublicKeyTypeEd25519(k) => MuxedAccount::Ed25519(k), + PublicKey::PublicKeyTypeEd25519(k) => PublicKey::PublicKeyTypeEd25519(k.into()), } } } -impl MuxedAccount { - #[must_use] - pub fn account_id(self) -> AccountId { - match self { - MuxedAccount::Ed25519(k) => AccountId(PublicKey::PublicKeyTypeEd25519(k)), - MuxedAccount::MuxedEd25519(m) => AccountId(PublicKey::PublicKeyTypeEd25519(m.ed25519)), +impl From for ScAddress { + fn from(t: PublicKey) -> Self { + ScAddress::Account(t.into()) + } +} +impl From<&PublicKey> for ScAddress { + fn from(t: &PublicKey) -> Self { + ScAddress::Account(t.into()) + } +} + +// From for AccountId already exists +impl From<&PublicKey> for AccountId { + fn from(public_key: &PublicKey) -> Self { + AccountId(public_key.into()) + } +} + +impl From for ScAddress { + fn from(account_id: AccountId) -> Self { + ScAddress::Account(account_id) + } +} +impl From<&AccountId> for ScAddress { + fn from(AccountId(public_key): &AccountId) -> Self { + ScAddress::Account(public_key.into()) + } +} + +impl From<&PublicKey> for ScVal { + fn from(public_key: &PublicKey) -> Self { + ScVal::Address(public_key.into()) + } +} + +impl From for ScVal { + fn from(public_key: PublicKey) -> Self { + ScVal::Address(public_key.into()) + } +} + +impl From for MuxedAccount { + fn from(account_id: AccountId) -> Self { + account_id.0.into() + } +} +impl From<&AccountId> for MuxedAccount { + fn from(AccountId(public_key): &AccountId) -> Self { + public_key.into() + } +} + +impl From<&AccountId> for AccountId { + fn from(AccountId(public_key): &AccountId) -> Self { + AccountId(public_key.into()) + } +} + +// MuxedAccount conversions +impl From for AccountId { + fn from(muxed_account: MuxedAccount) -> Self { + (&muxed_account).into() + } +} +impl From<&MuxedAccount> for AccountId { + fn from(muxed_account: &MuxedAccount) -> Self { + match muxed_account { + MuxedAccount::Ed25519(k) => AccountId(PublicKey::PublicKeyTypeEd25519(k.into())), + MuxedAccount::MuxedEd25519(MuxedAccountMed25519 { ed25519, .. }) => { + AccountId(PublicKey::PublicKeyTypeEd25519(ed25519.into())) + } + } + } +} + +impl From for ScAddress { + fn from(t: MuxedAccount) -> Self { + ScAddress::Account(t.into()) + } +} +impl From<&MuxedAccount> for ScAddress { + fn from(t: &MuxedAccount) -> Self { + ScAddress::Account(t.into()) + } +} + +impl From<&MuxedAccount> for MuxedAccount { + fn from(value: &MuxedAccount) -> Self { + match value { + MuxedAccount::Ed25519(k) => MuxedAccount::Ed25519(k.into()), + MuxedAccount::MuxedEd25519(MuxedAccountMed25519 { ed25519, id }) => { + MuxedAccount::MuxedEd25519(MuxedAccountMed25519 { + ed25519: ed25519.into(), + id: *id, + }) + } + } + } +} + +impl From<&ScAddress> for ScAddress { + fn from(sc_address: &ScAddress) -> Self { + match sc_address { + ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(k)))) => { + ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(*k)))) + } + ScAddress::Contract(Hash(h)) => ScAddress::Contract(Hash(*h)), } } } + +impl From for ScVal { + fn from(sc_address: ScAddress) -> Self { + ScVal::Address(sc_address) + } +} + +impl From<&ScAddress> for ScVal { + fn from(sc_address: &ScAddress) -> Self { + let sc_address: ScAddress = sc_address.into(); + sc_address.into() + } +} + +impl From<&Uint256> for Uint256 { + fn from(Uint256(k): &Uint256) -> Self { + Uint256(*k) + } +} + +impl From<&[u8; 32]> for Uint256 { + fn from(k: &[u8; 32]) -> Self { + Uint256(*k) + } +} + +impl From<&Uint256> for [u8; 32] { + fn from(Uint256(k): &Uint256) -> Self { + *k + } +} diff --git a/src/curr/asset_conversions.rs b/src/curr/asset_conversions.rs new file mode 100644 index 00000000..21b86d73 --- /dev/null +++ b/src/curr/asset_conversions.rs @@ -0,0 +1,76 @@ +use super::{ + AlphaNum12, AlphaNum4, Asset, AssetCode12, AssetCode4, ChangeTrustAsset, ContractIdPreimage, +}; +#[cfg(feature = "sha2")] +use super::{Hash, HashIdPreimage, HashIdPreimageContractId}; + +#[cfg(feature = "sha2")] +impl Asset { + pub fn into_contract_id( + self, + network_passphrase: &str, + ) -> Result { + let network_id = Hash::hash_bytes(network_passphrase); + HashIdPreimage::ContractId(HashIdPreimageContractId { + network_id, + contract_id_preimage: self.into(), + }) + .try_into() + } +} + +impl From for ContractIdPreimage { + fn from(value: Asset) -> Self { + ContractIdPreimage::Asset(value) + } +} + +impl From for ChangeTrustAsset { + fn from(asset: Asset) -> Self { + match asset { + Asset::CreditAlphanum4(asset) => ChangeTrustAsset::CreditAlphanum4(asset), + Asset::CreditAlphanum12(asset) => ChangeTrustAsset::CreditAlphanum12(asset), + Asset::Native => ChangeTrustAsset::Native, + } + } +} + +impl From<&Asset> for ChangeTrustAsset { + fn from(asset: &Asset) -> Self { + match asset { + Asset::CreditAlphanum4(asset) => ChangeTrustAsset::CreditAlphanum4(asset.into()), + Asset::CreditAlphanum12(asset) => ChangeTrustAsset::CreditAlphanum12(asset.into()), + Asset::Native => ChangeTrustAsset::Native, + } + } +} + +impl From<&AssetCode4> for AssetCode4 { + fn from(AssetCode4(inner): &AssetCode4) -> Self { + AssetCode4(*inner) + } +} + +impl From<&AssetCode12> for AssetCode12 { + fn from(AssetCode12(inner): &AssetCode12) -> Self { + AssetCode12(*inner) + } +} + +impl From<&AlphaNum4> for AlphaNum4 { + fn from(AlphaNum4 { asset_code, issuer }: &AlphaNum4) -> Self { + AlphaNum4 { + asset_code: asset_code.into(), + issuer: issuer.into(), + } + } +} + +impl From<&AlphaNum12> for AlphaNum12 { + fn from(AlphaNum12 { asset_code, issuer }: &AlphaNum12) -> Self { + AlphaNum12 { + asset_code: asset_code.into(), + issuer: issuer.into(), + } + } +} diff --git a/src/curr/bytes_conversions.rs b/src/curr/bytes_conversions.rs new file mode 100644 index 00000000..30fec326 --- /dev/null +++ b/src/curr/bytes_conversions.rs @@ -0,0 +1,7 @@ +use super::{BytesM, ScVal}; + +impl From for ScVal { + fn from(value: BytesM) -> Self { + ScVal::Bytes(value.into()) + } +} diff --git a/src/curr/contract_conversions.rs b/src/curr/contract_conversions.rs new file mode 100644 index 00000000..75f92fcd --- /dev/null +++ b/src/curr/contract_conversions.rs @@ -0,0 +1,118 @@ +use super::{ + Hash, HostFunction, InvokeContractArgs, InvokeHostFunctionOp, Operation, OperationBody, + ScAddress, VecM, +}; + +#[cfg(feature = "alloc")] +mod stellar_strkey_contract { + use super::super::{Error, ScVal}; + use super::*; + impl From for stellar_strkey::Contract { + fn from(v: Hash) -> Self { + stellar_strkey::Contract(v.0) + } + } + impl From<&Hash> for stellar_strkey::Contract { + fn from(v: &Hash) -> Self { + stellar_strkey::Contract(v.into()) + } + } + + impl From for Hash { + fn from(v: stellar_strkey::Contract) -> Self { + Hash(v.0) + } + } + impl From<&stellar_strkey::Contract> for Hash { + fn from(stellar_strkey::Contract(bytes): &stellar_strkey::Contract) -> Self { + Hash(*bytes) + } + } + + impl From for ScAddress { + fn from(v: stellar_strkey::Contract) -> Self { + ScAddress::Contract(v.into()) + } + } + impl From<&stellar_strkey::Contract> for ScAddress { + fn from(v: &stellar_strkey::Contract) -> Self { + ScAddress::Contract(v.into()) + } + } + + impl TryFrom for stellar_strkey::Contract { + type Error = Error; + fn try_from(sc_address: ScAddress) -> Result { + match sc_address { + ScAddress::Contract(c) => Ok(c.into()), + _ => Err(Error::Invalid), + } + } + } + + impl From for ScVal { + fn from(contract: stellar_strkey::Contract) -> Self { + ScVal::Address(contract.into()) + } + } + + impl From<&stellar_strkey::Contract> for ScVal { + fn from(contract: &stellar_strkey::Contract) -> Self { + ScVal::Address(contract.into()) + } + } +} + +impl From<&Hash> for [u8; 32] { + fn from(Hash(bytes): &Hash) -> Self { + *bytes + } +} + +impl From for ScAddress { + fn from(hash: Hash) -> Self { + ScAddress::Contract(hash) + } +} + +impl From<&Hash> for ScAddress { + fn from(hash: &Hash) -> Self { + ScAddress::Contract(hash.into()) + } +} + +impl From<&Hash> for Hash { + fn from(Hash(bytes): &Hash) -> Self { + Hash(*bytes) + } +} + +impl From for HostFunction { + fn from(parameters: InvokeContractArgs) -> Self { + HostFunction::InvokeContract(parameters) + } +} + +impl From for Operation { + fn from(parameters: InvokeContractArgs) -> Self { + Operation { + source_account: None, + body: OperationBody::InvokeHostFunction(InvokeHostFunctionOp { + host_function: parameters.into(), + auth: VecM::default(), + }), + } + } +} + +impl From for Operation { + fn from(host_function: HostFunction) -> Self { + Operation { + source_account: None, + body: OperationBody::InvokeHostFunction(InvokeHostFunctionOp { + host_function, + auth: VecM::default(), + }), + } + } +} diff --git a/src/curr/hash.rs b/src/curr/hash.rs new file mode 100644 index 00000000..7605d4ae --- /dev/null +++ b/src/curr/hash.rs @@ -0,0 +1,9 @@ +#[cfg(feature = "sha2")] +mod bytes; + +#[cfg(feature = "hex")] +impl super::Hash { + pub fn from_hex(s: &str) -> Result { + Ok(super::Hash(crate::hex::padded_hex_from_str(s)?)) + } +} diff --git a/src/curr/hash/bytes.rs b/src/curr/hash/bytes.rs new file mode 100644 index 00000000..b007fb3a --- /dev/null +++ b/src/curr/hash/bytes.rs @@ -0,0 +1,28 @@ +use super::super::{Hash, HashIdPreimage, Limits, WriteXdr}; + +use sha2::{Digest, Sha256}; + +impl Hash { + pub fn hash_bytes(bytes: impl AsRef<[u8]>) -> Self { + Hash(Sha256::digest(bytes.as_ref()).into()) + } +} + +impl TryFrom for Hash { + type Error = super::super::Error; + fn try_from(value: HashIdPreimage) -> Result { + Ok(Hash::hash_bytes(&value.to_xdr(Limits::none())?)) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom for stellar_strkey::Contract { + type Error = super::super::Error; + fn try_from(value: HashIdPreimage) -> Result { + let hash: Hash = match &value { + HashIdPreimage::ContractId(_) => value.try_into()?, + _ => return Err(Self::Error::Invalid), + }; + Ok(hash.into()) + } +} diff --git a/src/curr/mod.rs b/src/curr/mod.rs index 3a79be3b..e31237d7 100644 --- a/src/curr/mod.rs +++ b/src/curr/mod.rs @@ -1,12 +1,17 @@ mod generated; pub use generated::*; +mod hash; mod jsonschema; mod str; +mod bytes_conversions; +mod contract_conversions; mod scval_conversions; pub use scval_conversions::*; mod account_conversions; +mod asset_conversions; +mod num_conversions; mod transaction_conversions; mod scval_validations; diff --git a/src/curr/num_conversions.rs b/src/curr/num_conversions.rs new file mode 100644 index 00000000..743dce8e --- /dev/null +++ b/src/curr/num_conversions.rs @@ -0,0 +1,117 @@ +use core::str::FromStr; + +use super::{Int128Parts, Int256Parts, UInt128Parts, UInt256Parts}; + +impl From<(u128, u128)> for UInt256Parts { + fn from((hi, lo): (u128, u128)) -> Self { + let UInt128Parts { + hi: hi_hi, + lo: hi_lo, + } = hi.into(); + let UInt128Parts { + hi: lo_hi, + lo: lo_lo, + } = lo.into(); + UInt256Parts { + hi_hi, + hi_lo, + lo_hi, + lo_lo, + } + } +} + +impl From for (u128, u128) { + fn from(parts: UInt256Parts) -> Self { + let hi = (u128::from(parts.hi_hi) << 64) | u128::from(parts.hi_lo); + let lo = (u128::from(parts.lo_hi) << 64) | u128::from(parts.lo_lo); + (hi, lo) + } +} + +impl From<(i128, i128)> for Int256Parts { + fn from((hi, lo): (i128, i128)) -> Self { + let Int128Parts { + hi: hi_hi, + lo: hi_lo, + } = hi.into(); + let UInt128Parts { + hi: lo_hi, + lo: lo_lo, + } = (lo as u128).into(); + Int256Parts { + hi_hi, + hi_lo, + lo_hi, + lo_lo, + } + } +} + +impl From for (i128, i128) { + fn from(parts: Int256Parts) -> Self { + let hi = (i128::from(parts.hi_hi) << 64) | i128::from(parts.hi_lo); + let lo = (i128::from(parts.lo_hi) << 64) | i128::from(parts.lo_lo); + (hi, lo) + } +} + +impl From for UInt128Parts { + fn from(val: u128) -> Self { + let hi = (val >> 64) as u64; + let lo = val as u64; + let hi: [u8; 8] = hi.to_be_bytes(); + let lo: [u8; 8] = lo.to_be_bytes(); + Self { + hi: u64::from_be_bytes(hi), + lo: u64::from_be_bytes(lo), + } + } +} + +impl From for u128 { + fn from(parts: UInt128Parts) -> Self { + let hi: [u8; 8] = parts.hi.to_be_bytes(); + let lo: [u8; 8] = parts.lo.to_be_bytes(); + let hi = u64::from_be_bytes(hi); + let lo = u64::from_be_bytes(lo); + (hi as u128) << 64 | lo as u128 + } +} + +impl From for Int128Parts { + fn from(val: i128) -> Self { + let hi = (val >> 64) as u64; + let lo = val as i64; + let hi: [u8; 8] = hi.to_be_bytes(); + let lo: [u8; 8] = lo.to_be_bytes(); + Int128Parts { + hi: i64::from_be_bytes(hi), + lo: u64::from_be_bytes(lo), + } + } +} + +impl From for i128 { + fn from(parts: Int128Parts) -> Self { + let hi: [u8; 8] = parts.hi.to_be_bytes(); + let lo: [u8; 8] = parts.lo.to_be_bytes(); + let hi = i64::from_be_bytes(hi); + let lo = u64::from_be_bytes(lo); + (hi as i128) << 64 | lo as i128 + } +} + +impl FromStr for UInt128Parts { + type Err = super::Error; + fn from_str(s: &str) -> Result { + Ok(u128::from_str(s).map_err(|_| Self::Err::Invalid)?.into()) + } +} + +impl FromStr for Int128Parts { + type Err = super::Error; + fn from_str(s: &str) -> Result { + Ok(i128::from_str(s).map_err(|_| Self::Err::Invalid)?.into()) + } +} diff --git a/src/curr/scval_conversions.rs b/src/curr/scval_conversions.rs index 8c42eef6..5c34527c 100644 --- a/src/curr/scval_conversions.rs +++ b/src/curr/scval_conversions.rs @@ -1,5 +1,6 @@ use super::{ - Int128Parts, ScBytes, ScError, ScMap, ScMapEntry, ScSymbol, ScVal, ScVec, UInt128Parts, + Int128Parts, ScBytes, ScError, ScMap, ScMapEntry, ScString, ScSymbol, ScVal, ScVec, + UInt128Parts, }; #[cfg(all(not(feature = "std"), feature = "alloc"))] @@ -332,6 +333,55 @@ impl TryFrom<&'static str> for ScSymbol { } } +impl From for ScVal { + fn from(v: ScString) -> Self { + ScVal::String(v) + } +} + +impl TryFrom for ScString { + type Error = (); + fn try_from(v: ScVal) -> Result { + if let ScVal::String(s) = v { + Ok(s) + } else { + Err(()) + } + } +} + +#[cfg(feature = "alloc")] +impl TryFrom for ScString { + type Error = (); + fn try_from(v: String) -> Result { + Ok(ScString(v.try_into().map_err(|_| ())?)) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&String> for ScString { + type Error = (); + fn try_from(v: &String) -> Result { + Ok(ScString(v.try_into().map_err(|_| ())?)) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&str> for ScString { + type Error = (); + fn try_from(v: &str) -> Result { + Ok(ScString(v.try_into().map_err(|_| ())?)) + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static str> for ScString { + type Error = (); + fn try_from(v: &'static str) -> Result { + Ok(ScString(v.try_into().map_err(|_| ())?)) + } +} + #[cfg(feature = "alloc")] impl TryFrom> for ScVal { type Error = (); diff --git a/src/curr/str.rs b/src/curr/str.rs index c8fe36cb..9b4bfa85 100644 --- a/src/curr/str.rs +++ b/src/curr/str.rs @@ -14,7 +14,8 @@ //# - SignerKeyEd25519SignedPayload //# - NodeId //# -//# ## Asset Codes +//# ## Asset Types +//# - Asset //# - AssetCode //# - AssetCode4 //# - AssetCode12 @@ -24,9 +25,9 @@ #![cfg(feature = "alloc")] use super::{ - AccountId, AssetCode, AssetCode12, AssetCode4, ClaimableBalanceId, Error, Hash, MuxedAccount, - MuxedAccountMed25519, NodeId, PublicKey, ScAddress, SignerKey, SignerKeyEd25519SignedPayload, - Uint256, + AccountId, AlphaNum12, AlphaNum4, Asset, AssetCode, AssetCode12, AssetCode4, + ClaimableBalanceId, Error, Hash, MuxedAccount, MuxedAccountMed25519, NodeId, PublicKey, + ScAddress, SignerKey, SignerKeyEd25519SignedPayload, Uint256, }; impl From for Error { @@ -341,6 +342,29 @@ impl core::fmt::Display for AssetCode { } } +impl core::str::FromStr for Asset { + type Err = Error; + + fn from_str(value: &str) -> Result { + if value == "native" { + return Ok(Asset::Native); + } + let mut iter = value.splitn(2, ':'); + let (Some(code), Some(issuer), None) = (iter.next(), iter.next(), iter.next()) else { + return Err(Error::Invalid); + }; + let issuer = issuer.parse()?; + Ok(match code.parse()? { + AssetCode::CreditAlphanum4(asset_code) => { + Asset::CreditAlphanum4(AlphaNum4 { asset_code, issuer }) + } + AssetCode::CreditAlphanum12(asset_code) => { + Asset::CreditAlphanum12(AlphaNum12 { asset_code, issuer }) + } + }) + } +} + impl core::str::FromStr for ClaimableBalanceId { type Err = Error; fn from_str(s: &str) -> core::result::Result { diff --git a/src/curr/transaction_conversions.rs b/src/curr/transaction_conversions.rs index a821a51f..b680fa54 100644 --- a/src/curr/transaction_conversions.rs +++ b/src/curr/transaction_conversions.rs @@ -3,6 +3,52 @@ use super::{ TransactionV1Envelope, VecM, }; +#[cfg(feature = "alloc")] +use super::{Error, Memo, MuxedAccount, Operation, Preconditions, SequenceNumber, TransactionExt}; +#[cfg(feature = "sha2")] +use super::{ + Hash, Limits, TransactionSignaturePayload, TransactionSignaturePayloadTaggedTransaction, + WriteXdr, +}; + +impl Transaction { + #[cfg(feature = "alloc")] + pub fn new_tx( + source_account: impl Into, + fee: u32, + seq_num: impl Into, + operation: Operation, + ) -> Transaction { + Transaction { + source_account: source_account.into(), + fee, + seq_num: seq_num.into(), + cond: Preconditions::None, + memo: Memo::None, + operations: [operation].try_into().unwrap(), + ext: TransactionExt::V0, + } + } + #[cfg(feature = "alloc")] + pub fn add_operation(mut self, operation: Operation) -> Result { + let mut ops = self.operations.to_vec(); + ops.push(operation); + self.operations = ops.try_into().map_err(|_| Error::Invalid)?; + Ok(self) + } + + #[cfg(feature = "sha2")] + pub fn hash(&self, network_passphrase: &str) -> Result { + let signature_payload = TransactionSignaturePayload { + network_id: Hash::hash_bytes(network_passphrase), + tagged_transaction: TransactionSignaturePayloadTaggedTransaction::Tx(self.clone()), + }; + signature_payload + .to_xdr(Limits::none()) + .map(Hash::hash_bytes) + } +} + impl From for TransactionEnvelope { fn from(tx: Transaction) -> Self { TransactionEnvelope::Tx(TransactionV1Envelope { diff --git a/src/hex.rs b/src/hex.rs new file mode 100644 index 00000000..8af3d984 --- /dev/null +++ b/src/hex.rs @@ -0,0 +1,11 @@ +pub(crate) fn padded_hex_from_str(s: &str) -> Result<[u8; 32], hex::FromHexError> { + let n = 32; + if s.len() > n * 2 { + return Err(hex::FromHexError::InvalidStringLength); + } + let mut decoded = [0u8; 32]; + let mut padded = [b'0'; 64]; // 32 bytes * 2 chars per byte + padded[(64 - s.len())..].copy_from_slice(s.as_bytes()); + hex::decode_to_slice(padded, &mut decoded)?; + Ok(decoded) +} diff --git a/src/lib.rs b/src/lib.rs index 60583ea1..e7751320 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,3 +135,6 @@ pub mod next; #[cfg(feature = "cli")] pub mod cli; + +#[cfg(feature = "hex")] +pub mod hex; diff --git a/src/next/account_conversions.rs b/src/next/account_conversions.rs index 19378d2b..9655ae75 100644 --- a/src/next/account_conversions.rs +++ b/src/next/account_conversions.rs @@ -1,25 +1,322 @@ -use super::{AccountId, MuxedAccount, PublicKey}; +use super::{ + AccountId, Hash, MuxedAccount, MuxedAccountMed25519, PublicKey, ScAddress, ScVal, Uint256, +}; -impl From for MuxedAccount { - fn from(account_id: AccountId) -> Self { - account_id.0.into() +#[cfg(feature = "alloc")] +mod strkey { + use super::super::Error; + use super::*; + impl From for PublicKey { + fn from(k: stellar_strkey::ed25519::PublicKey) -> Self { + PublicKey::PublicKeyTypeEd25519(k.0.into()) + } + } + impl From<&stellar_strkey::ed25519::PublicKey> for PublicKey { + fn from(k: &stellar_strkey::ed25519::PublicKey) -> Self { + PublicKey::PublicKeyTypeEd25519(k.0.into()) + } + } + + impl From for AccountId { + fn from(k: stellar_strkey::ed25519::PublicKey) -> Self { + AccountId(k.into()) + } + } + impl From<&stellar_strkey::ed25519::PublicKey> for AccountId { + fn from(k: &stellar_strkey::ed25519::PublicKey) -> Self { + AccountId(k.into()) + } + } + + impl From for ScAddress { + fn from(t: stellar_strkey::ed25519::PublicKey) -> Self { + ScAddress::Account(t.into()) + } + } + impl From<&stellar_strkey::ed25519::PublicKey> for ScAddress { + fn from(t: &stellar_strkey::ed25519::PublicKey) -> Self { + ScAddress::Account(t.into()) + } + } + + impl From for ScVal { + fn from(k: stellar_strkey::ed25519::PublicKey) -> Self { + ScVal::Address(k.into()) + } + } + impl From<&stellar_strkey::ed25519::PublicKey> for ScVal { + fn from(k: &stellar_strkey::ed25519::PublicKey) -> Self { + ScVal::Address(k.into()) + } + } + + impl From for PublicKey { + fn from(k: stellar_strkey::ed25519::MuxedAccount) -> Self { + PublicKey::PublicKeyTypeEd25519(k.ed25519.into()) + } + } + impl From<&stellar_strkey::ed25519::MuxedAccount> for PublicKey { + fn from( + stellar_strkey::ed25519::MuxedAccount{ ed25519, .. }: &stellar_strkey::ed25519::MuxedAccount, + ) -> Self { + PublicKey::PublicKeyTypeEd25519(ed25519.into()) + } + } + + impl From for AccountId { + fn from(k: stellar_strkey::ed25519::MuxedAccount) -> Self { + AccountId(k.into()) + } + } + impl From<&stellar_strkey::ed25519::MuxedAccount> for AccountId { + fn from(k: &stellar_strkey::ed25519::MuxedAccount) -> Self { + AccountId(k.into()) + } + } + + impl From for ScAddress { + fn from(t: stellar_strkey::ed25519::MuxedAccount) -> Self { + ScAddress::Account(t.into()) + } + } + impl From<&stellar_strkey::ed25519::MuxedAccount> for ScAddress { + fn from(t: &stellar_strkey::ed25519::MuxedAccount) -> Self { + ScAddress::Account(t.into()) + } + } + + impl From for ScVal { + fn from(k: stellar_strkey::ed25519::MuxedAccount) -> Self { + ScVal::Address(k.into()) + } + } + impl From<&stellar_strkey::ed25519::MuxedAccount> for ScVal { + fn from(k: &stellar_strkey::ed25519::MuxedAccount) -> Self { + ScVal::Address(k.into()) + } + } + + impl TryFrom<&stellar_strkey::Strkey> for ScAddress { + type Error = Error; + fn try_from(strkey: &stellar_strkey::Strkey) -> Result { + match strkey { + stellar_strkey::Strkey::PublicKeyEd25519(k) => Ok(ScAddress::Account(k.into())), + stellar_strkey::Strkey::MuxedAccountEd25519(m) => Ok(ScAddress::Account(m.into())), + stellar_strkey::Strkey::Contract(k) => Ok(ScAddress::Contract(k.into())), + _ => Err(Error::Invalid), + } + } + } + + impl From for stellar_strkey::ed25519::PublicKey { + fn from(k: PublicKey) -> Self { + (&k).into() + } + } + impl From<&PublicKey> for stellar_strkey::ed25519::PublicKey { + fn from(k: &PublicKey) -> Self { + match k { + PublicKey::PublicKeyTypeEd25519(k) => stellar_strkey::ed25519::PublicKey(k.into()), + } + } + } + impl From for stellar_strkey::Strkey { + fn from(sc_address: ScAddress) -> Self { + match sc_address { + ScAddress::Account(account_id) => { + stellar_strkey::Strkey::PublicKeyEd25519(account_id.into()) + } + ScAddress::Contract(contract) => stellar_strkey::Strkey::Contract(contract.into()), + } + } + } + impl From<&ScAddress> for stellar_strkey::Strkey { + fn from(sc_address: &ScAddress) -> Self { + match sc_address { + ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(k)))) => { + stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(*k)) + } + ScAddress::Contract(Hash(h)) => { + stellar_strkey::Strkey::Contract(stellar_strkey::Contract(*h)) + } + } + } + } + impl From for stellar_strkey::ed25519::PublicKey { + fn from(value: AccountId) -> Self { + match value { + AccountId(key) => key.into(), + } + } + } + impl From<&AccountId> for stellar_strkey::ed25519::PublicKey { + fn from(value: &AccountId) -> Self { + match value { + AccountId(key) => key.into(), + } + } } } impl From for MuxedAccount { fn from(public_key: PublicKey) -> Self { + (&public_key).into() + } +} +impl From<&PublicKey> for MuxedAccount { + fn from(public_key: &PublicKey) -> Self { + match public_key { + PublicKey::PublicKeyTypeEd25519(k) => MuxedAccount::Ed25519(k.into()), + } + } +} + +impl From<&PublicKey> for PublicKey { + fn from(public_key: &PublicKey) -> Self { match public_key { - PublicKey::PublicKeyTypeEd25519(k) => MuxedAccount::Ed25519(k), + PublicKey::PublicKeyTypeEd25519(k) => PublicKey::PublicKeyTypeEd25519(k.into()), } } } -impl MuxedAccount { - #[must_use] - pub fn account_id(self) -> AccountId { - match self { - MuxedAccount::Ed25519(k) => AccountId(PublicKey::PublicKeyTypeEd25519(k)), - MuxedAccount::MuxedEd25519(m) => AccountId(PublicKey::PublicKeyTypeEd25519(m.ed25519)), +impl From for ScAddress { + fn from(t: PublicKey) -> Self { + ScAddress::Account(t.into()) + } +} +impl From<&PublicKey> for ScAddress { + fn from(t: &PublicKey) -> Self { + ScAddress::Account(t.into()) + } +} + +// From for AccountId already exists +impl From<&PublicKey> for AccountId { + fn from(public_key: &PublicKey) -> Self { + AccountId(public_key.into()) + } +} + +impl From for ScAddress { + fn from(account_id: AccountId) -> Self { + ScAddress::Account(account_id) + } +} +impl From<&AccountId> for ScAddress { + fn from(AccountId(public_key): &AccountId) -> Self { + ScAddress::Account(public_key.into()) + } +} + +impl From<&PublicKey> for ScVal { + fn from(public_key: &PublicKey) -> Self { + ScVal::Address(public_key.into()) + } +} + +impl From for ScVal { + fn from(public_key: PublicKey) -> Self { + ScVal::Address(public_key.into()) + } +} + +impl From for MuxedAccount { + fn from(account_id: AccountId) -> Self { + account_id.0.into() + } +} +impl From<&AccountId> for MuxedAccount { + fn from(AccountId(public_key): &AccountId) -> Self { + public_key.into() + } +} + +impl From<&AccountId> for AccountId { + fn from(AccountId(public_key): &AccountId) -> Self { + AccountId(public_key.into()) + } +} + +// MuxedAccount conversions +impl From for AccountId { + fn from(muxed_account: MuxedAccount) -> Self { + (&muxed_account).into() + } +} +impl From<&MuxedAccount> for AccountId { + fn from(muxed_account: &MuxedAccount) -> Self { + match muxed_account { + MuxedAccount::Ed25519(k) => AccountId(PublicKey::PublicKeyTypeEd25519(k.into())), + MuxedAccount::MuxedEd25519(MuxedAccountMed25519 { ed25519, .. }) => { + AccountId(PublicKey::PublicKeyTypeEd25519(ed25519.into())) + } + } + } +} + +impl From for ScAddress { + fn from(t: MuxedAccount) -> Self { + ScAddress::Account(t.into()) + } +} +impl From<&MuxedAccount> for ScAddress { + fn from(t: &MuxedAccount) -> Self { + ScAddress::Account(t.into()) + } +} + +impl From<&MuxedAccount> for MuxedAccount { + fn from(value: &MuxedAccount) -> Self { + match value { + MuxedAccount::Ed25519(k) => MuxedAccount::Ed25519(k.into()), + MuxedAccount::MuxedEd25519(MuxedAccountMed25519 { ed25519, id }) => { + MuxedAccount::MuxedEd25519(MuxedAccountMed25519 { + ed25519: ed25519.into(), + id: *id, + }) + } + } + } +} + +impl From<&ScAddress> for ScAddress { + fn from(sc_address: &ScAddress) -> Self { + match sc_address { + ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(k)))) => { + ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(*k)))) + } + ScAddress::Contract(Hash(h)) => ScAddress::Contract(Hash(*h)), } } } + +impl From for ScVal { + fn from(sc_address: ScAddress) -> Self { + ScVal::Address(sc_address) + } +} + +impl From<&ScAddress> for ScVal { + fn from(sc_address: &ScAddress) -> Self { + let sc_address: ScAddress = sc_address.into(); + sc_address.into() + } +} + +impl From<&Uint256> for Uint256 { + fn from(Uint256(k): &Uint256) -> Self { + Uint256(*k) + } +} + +impl From<&[u8; 32]> for Uint256 { + fn from(k: &[u8; 32]) -> Self { + Uint256(*k) + } +} + +impl From<&Uint256> for [u8; 32] { + fn from(Uint256(k): &Uint256) -> Self { + *k + } +} diff --git a/src/next/asset_conversions.rs b/src/next/asset_conversions.rs new file mode 100644 index 00000000..21b86d73 --- /dev/null +++ b/src/next/asset_conversions.rs @@ -0,0 +1,76 @@ +use super::{ + AlphaNum12, AlphaNum4, Asset, AssetCode12, AssetCode4, ChangeTrustAsset, ContractIdPreimage, +}; +#[cfg(feature = "sha2")] +use super::{Hash, HashIdPreimage, HashIdPreimageContractId}; + +#[cfg(feature = "sha2")] +impl Asset { + pub fn into_contract_id( + self, + network_passphrase: &str, + ) -> Result { + let network_id = Hash::hash_bytes(network_passphrase); + HashIdPreimage::ContractId(HashIdPreimageContractId { + network_id, + contract_id_preimage: self.into(), + }) + .try_into() + } +} + +impl From for ContractIdPreimage { + fn from(value: Asset) -> Self { + ContractIdPreimage::Asset(value) + } +} + +impl From for ChangeTrustAsset { + fn from(asset: Asset) -> Self { + match asset { + Asset::CreditAlphanum4(asset) => ChangeTrustAsset::CreditAlphanum4(asset), + Asset::CreditAlphanum12(asset) => ChangeTrustAsset::CreditAlphanum12(asset), + Asset::Native => ChangeTrustAsset::Native, + } + } +} + +impl From<&Asset> for ChangeTrustAsset { + fn from(asset: &Asset) -> Self { + match asset { + Asset::CreditAlphanum4(asset) => ChangeTrustAsset::CreditAlphanum4(asset.into()), + Asset::CreditAlphanum12(asset) => ChangeTrustAsset::CreditAlphanum12(asset.into()), + Asset::Native => ChangeTrustAsset::Native, + } + } +} + +impl From<&AssetCode4> for AssetCode4 { + fn from(AssetCode4(inner): &AssetCode4) -> Self { + AssetCode4(*inner) + } +} + +impl From<&AssetCode12> for AssetCode12 { + fn from(AssetCode12(inner): &AssetCode12) -> Self { + AssetCode12(*inner) + } +} + +impl From<&AlphaNum4> for AlphaNum4 { + fn from(AlphaNum4 { asset_code, issuer }: &AlphaNum4) -> Self { + AlphaNum4 { + asset_code: asset_code.into(), + issuer: issuer.into(), + } + } +} + +impl From<&AlphaNum12> for AlphaNum12 { + fn from(AlphaNum12 { asset_code, issuer }: &AlphaNum12) -> Self { + AlphaNum12 { + asset_code: asset_code.into(), + issuer: issuer.into(), + } + } +} diff --git a/src/next/bytes_conversions.rs b/src/next/bytes_conversions.rs new file mode 100644 index 00000000..30fec326 --- /dev/null +++ b/src/next/bytes_conversions.rs @@ -0,0 +1,7 @@ +use super::{BytesM, ScVal}; + +impl From for ScVal { + fn from(value: BytesM) -> Self { + ScVal::Bytes(value.into()) + } +} diff --git a/src/next/contract_conversions.rs b/src/next/contract_conversions.rs new file mode 100644 index 00000000..75f92fcd --- /dev/null +++ b/src/next/contract_conversions.rs @@ -0,0 +1,118 @@ +use super::{ + Hash, HostFunction, InvokeContractArgs, InvokeHostFunctionOp, Operation, OperationBody, + ScAddress, VecM, +}; + +#[cfg(feature = "alloc")] +mod stellar_strkey_contract { + use super::super::{Error, ScVal}; + use super::*; + impl From for stellar_strkey::Contract { + fn from(v: Hash) -> Self { + stellar_strkey::Contract(v.0) + } + } + impl From<&Hash> for stellar_strkey::Contract { + fn from(v: &Hash) -> Self { + stellar_strkey::Contract(v.into()) + } + } + + impl From for Hash { + fn from(v: stellar_strkey::Contract) -> Self { + Hash(v.0) + } + } + impl From<&stellar_strkey::Contract> for Hash { + fn from(stellar_strkey::Contract(bytes): &stellar_strkey::Contract) -> Self { + Hash(*bytes) + } + } + + impl From for ScAddress { + fn from(v: stellar_strkey::Contract) -> Self { + ScAddress::Contract(v.into()) + } + } + impl From<&stellar_strkey::Contract> for ScAddress { + fn from(v: &stellar_strkey::Contract) -> Self { + ScAddress::Contract(v.into()) + } + } + + impl TryFrom for stellar_strkey::Contract { + type Error = Error; + fn try_from(sc_address: ScAddress) -> Result { + match sc_address { + ScAddress::Contract(c) => Ok(c.into()), + _ => Err(Error::Invalid), + } + } + } + + impl From for ScVal { + fn from(contract: stellar_strkey::Contract) -> Self { + ScVal::Address(contract.into()) + } + } + + impl From<&stellar_strkey::Contract> for ScVal { + fn from(contract: &stellar_strkey::Contract) -> Self { + ScVal::Address(contract.into()) + } + } +} + +impl From<&Hash> for [u8; 32] { + fn from(Hash(bytes): &Hash) -> Self { + *bytes + } +} + +impl From for ScAddress { + fn from(hash: Hash) -> Self { + ScAddress::Contract(hash) + } +} + +impl From<&Hash> for ScAddress { + fn from(hash: &Hash) -> Self { + ScAddress::Contract(hash.into()) + } +} + +impl From<&Hash> for Hash { + fn from(Hash(bytes): &Hash) -> Self { + Hash(*bytes) + } +} + +impl From for HostFunction { + fn from(parameters: InvokeContractArgs) -> Self { + HostFunction::InvokeContract(parameters) + } +} + +impl From for Operation { + fn from(parameters: InvokeContractArgs) -> Self { + Operation { + source_account: None, + body: OperationBody::InvokeHostFunction(InvokeHostFunctionOp { + host_function: parameters.into(), + auth: VecM::default(), + }), + } + } +} + +impl From for Operation { + fn from(host_function: HostFunction) -> Self { + Operation { + source_account: None, + body: OperationBody::InvokeHostFunction(InvokeHostFunctionOp { + host_function, + auth: VecM::default(), + }), + } + } +} diff --git a/src/next/hash.rs b/src/next/hash.rs new file mode 100644 index 00000000..7605d4ae --- /dev/null +++ b/src/next/hash.rs @@ -0,0 +1,9 @@ +#[cfg(feature = "sha2")] +mod bytes; + +#[cfg(feature = "hex")] +impl super::Hash { + pub fn from_hex(s: &str) -> Result { + Ok(super::Hash(crate::hex::padded_hex_from_str(s)?)) + } +} diff --git a/src/next/hash/bytes.rs b/src/next/hash/bytes.rs new file mode 100644 index 00000000..b007fb3a --- /dev/null +++ b/src/next/hash/bytes.rs @@ -0,0 +1,28 @@ +use super::super::{Hash, HashIdPreimage, Limits, WriteXdr}; + +use sha2::{Digest, Sha256}; + +impl Hash { + pub fn hash_bytes(bytes: impl AsRef<[u8]>) -> Self { + Hash(Sha256::digest(bytes.as_ref()).into()) + } +} + +impl TryFrom for Hash { + type Error = super::super::Error; + fn try_from(value: HashIdPreimage) -> Result { + Ok(Hash::hash_bytes(&value.to_xdr(Limits::none())?)) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom for stellar_strkey::Contract { + type Error = super::super::Error; + fn try_from(value: HashIdPreimage) -> Result { + let hash: Hash = match &value { + HashIdPreimage::ContractId(_) => value.try_into()?, + _ => return Err(Self::Error::Invalid), + }; + Ok(hash.into()) + } +} diff --git a/src/next/mod.rs b/src/next/mod.rs index 3a79be3b..e31237d7 100644 --- a/src/next/mod.rs +++ b/src/next/mod.rs @@ -1,12 +1,17 @@ mod generated; pub use generated::*; +mod hash; mod jsonschema; mod str; +mod bytes_conversions; +mod contract_conversions; mod scval_conversions; pub use scval_conversions::*; mod account_conversions; +mod asset_conversions; +mod num_conversions; mod transaction_conversions; mod scval_validations; diff --git a/src/next/num_conversions.rs b/src/next/num_conversions.rs new file mode 100644 index 00000000..743dce8e --- /dev/null +++ b/src/next/num_conversions.rs @@ -0,0 +1,117 @@ +use core::str::FromStr; + +use super::{Int128Parts, Int256Parts, UInt128Parts, UInt256Parts}; + +impl From<(u128, u128)> for UInt256Parts { + fn from((hi, lo): (u128, u128)) -> Self { + let UInt128Parts { + hi: hi_hi, + lo: hi_lo, + } = hi.into(); + let UInt128Parts { + hi: lo_hi, + lo: lo_lo, + } = lo.into(); + UInt256Parts { + hi_hi, + hi_lo, + lo_hi, + lo_lo, + } + } +} + +impl From for (u128, u128) { + fn from(parts: UInt256Parts) -> Self { + let hi = (u128::from(parts.hi_hi) << 64) | u128::from(parts.hi_lo); + let lo = (u128::from(parts.lo_hi) << 64) | u128::from(parts.lo_lo); + (hi, lo) + } +} + +impl From<(i128, i128)> for Int256Parts { + fn from((hi, lo): (i128, i128)) -> Self { + let Int128Parts { + hi: hi_hi, + lo: hi_lo, + } = hi.into(); + let UInt128Parts { + hi: lo_hi, + lo: lo_lo, + } = (lo as u128).into(); + Int256Parts { + hi_hi, + hi_lo, + lo_hi, + lo_lo, + } + } +} + +impl From for (i128, i128) { + fn from(parts: Int256Parts) -> Self { + let hi = (i128::from(parts.hi_hi) << 64) | i128::from(parts.hi_lo); + let lo = (i128::from(parts.lo_hi) << 64) | i128::from(parts.lo_lo); + (hi, lo) + } +} + +impl From for UInt128Parts { + fn from(val: u128) -> Self { + let hi = (val >> 64) as u64; + let lo = val as u64; + let hi: [u8; 8] = hi.to_be_bytes(); + let lo: [u8; 8] = lo.to_be_bytes(); + Self { + hi: u64::from_be_bytes(hi), + lo: u64::from_be_bytes(lo), + } + } +} + +impl From for u128 { + fn from(parts: UInt128Parts) -> Self { + let hi: [u8; 8] = parts.hi.to_be_bytes(); + let lo: [u8; 8] = parts.lo.to_be_bytes(); + let hi = u64::from_be_bytes(hi); + let lo = u64::from_be_bytes(lo); + (hi as u128) << 64 | lo as u128 + } +} + +impl From for Int128Parts { + fn from(val: i128) -> Self { + let hi = (val >> 64) as u64; + let lo = val as i64; + let hi: [u8; 8] = hi.to_be_bytes(); + let lo: [u8; 8] = lo.to_be_bytes(); + Int128Parts { + hi: i64::from_be_bytes(hi), + lo: u64::from_be_bytes(lo), + } + } +} + +impl From for i128 { + fn from(parts: Int128Parts) -> Self { + let hi: [u8; 8] = parts.hi.to_be_bytes(); + let lo: [u8; 8] = parts.lo.to_be_bytes(); + let hi = i64::from_be_bytes(hi); + let lo = u64::from_be_bytes(lo); + (hi as i128) << 64 | lo as i128 + } +} + +impl FromStr for UInt128Parts { + type Err = super::Error; + fn from_str(s: &str) -> Result { + Ok(u128::from_str(s).map_err(|_| Self::Err::Invalid)?.into()) + } +} + +impl FromStr for Int128Parts { + type Err = super::Error; + fn from_str(s: &str) -> Result { + Ok(i128::from_str(s).map_err(|_| Self::Err::Invalid)?.into()) + } +} diff --git a/src/next/scval_conversions.rs b/src/next/scval_conversions.rs index dd64b316..32a27474 100644 --- a/src/next/scval_conversions.rs +++ b/src/next/scval_conversions.rs @@ -1,5 +1,6 @@ use super::{ - Int128Parts, ScBytes, ScError, ScMap, ScMapEntry, ScSymbol, ScVal, ScVec, UInt128Parts, + Int128Parts, ScBytes, ScError, ScMap, ScMapEntry, ScString, ScSymbol, ScVal, ScVec, + UInt128Parts, }; #[cfg(all(not(feature = "std"), feature = "alloc"))] @@ -301,80 +302,83 @@ impl TryFrom for ScSymbol { } #[cfg(feature = "alloc")] -impl TryFrom for ScVal { +impl TryFrom for ScSymbol { type Error = (); - fn try_from(v: String) -> Result { - Ok(ScVal::Symbol(v.try_into()?)) + fn try_from(v: String) -> Result { + Ok(ScSymbol(v.try_into().map_err(|_| ())?)) } } #[cfg(feature = "alloc")] -impl TryFrom<&String> for ScVal { +impl TryFrom<&String> for ScSymbol { type Error = (); - fn try_from(v: &String) -> Result { - Ok(ScVal::Symbol(v.try_into()?)) + fn try_from(v: &String) -> Result { + Ok(ScSymbol(v.try_into().map_err(|_| ())?)) } } #[cfg(feature = "alloc")] -impl TryFrom for ScSymbol { +impl TryFrom<&str> for ScSymbol { type Error = (); - fn try_from(v: String) -> Result { + fn try_from(v: &str) -> Result { Ok(ScSymbol(v.try_into().map_err(|_| ())?)) } } -#[cfg(feature = "alloc")] -impl TryFrom<&String> for ScSymbol { +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static str> for ScSymbol { type Error = (); - fn try_from(v: &String) -> Result { + fn try_from(v: &'static str) -> Result { Ok(ScSymbol(v.try_into().map_err(|_| ())?)) } } -#[cfg(feature = "alloc")] -impl TryFrom<&str> for ScVal { - type Error = (); - fn try_from(v: &str) -> Result { - Ok(ScVal::Symbol(v.try_into()?)) +impl From for ScVal { + fn from(v: ScString) -> Self { + ScVal::String(v) } } -#[cfg(not(feature = "alloc"))] -impl TryFrom<&'static str> for ScVal { +impl TryFrom for ScString { type Error = (); - fn try_from(v: &'static str) -> Result { - Ok(ScVal::Symbol(v.try_into()?)) + fn try_from(v: ScVal) -> Result { + if let ScVal::String(s) = v { + Ok(s) + } else { + Err(()) + } } } #[cfg(feature = "alloc")] -impl TryFrom<&str> for ScSymbol { +impl TryFrom for ScString { type Error = (); - fn try_from(v: &str) -> Result { - Ok(ScSymbol(v.try_into().map_err(|_| ())?)) + fn try_from(v: String) -> Result { + Ok(ScString(v.try_into().map_err(|_| ())?)) } } -#[cfg(not(feature = "alloc"))] -impl TryFrom<&'static str> for ScSymbol { +#[cfg(feature = "alloc")] +impl TryFrom<&String> for ScString { type Error = (); - fn try_from(v: &'static str) -> Result { - Ok(ScSymbol(v.try_into().map_err(|_| ())?)) + fn try_from(v: &String) -> Result { + Ok(ScString(v.try_into().map_err(|_| ())?)) } } #[cfg(feature = "alloc")] -impl TryFrom for String { +impl TryFrom<&str> for ScString { type Error = (); - fn try_from(v: ScVal) -> Result { - if let ScVal::Symbol(s) = v { - // TODO: It might be worth distinguishing the error case where this - // is an invalid symbol with invalid characters. - Ok(s.0.into_utf8_string().map_err(|_| ())?) - } else { - Err(()) - } + fn try_from(v: &str) -> Result { + Ok(ScString(v.try_into().map_err(|_| ())?)) + } +} + +#[cfg(not(feature = "alloc"))] +impl TryFrom<&'static str> for ScString { + type Error = (); + fn try_from(v: &'static str) -> Result { + Ok(ScString(v.try_into().map_err(|_| ())?)) } } diff --git a/src/next/str.rs b/src/next/str.rs index 098dd4e3..9b4bfa85 100644 --- a/src/next/str.rs +++ b/src/next/str.rs @@ -14,7 +14,8 @@ //# - SignerKeyEd25519SignedPayload //# - NodeId //# -//# ## Asset Codes +//# ## Asset Types +//# - Asset //# - AssetCode //# - AssetCode4 //# - AssetCode12 @@ -24,9 +25,9 @@ #![cfg(feature = "alloc")] use super::{ - AccountId, AssetCode, AssetCode12, AssetCode4, ClaimableBalanceId, Error, Hash, MuxedAccount, - MuxedAccountMed25519, NodeId, PublicKey, ScAddress, SignerKey, SignerKeyEd25519SignedPayload, - Uint256, + AccountId, AlphaNum12, AlphaNum4, Asset, AssetCode, AssetCode12, AssetCode4, + ClaimableBalanceId, Error, Hash, MuxedAccount, MuxedAccountMed25519, NodeId, PublicKey, + ScAddress, SignerKey, SignerKeyEd25519SignedPayload, Uint256, }; impl From for Error { @@ -295,10 +296,21 @@ impl core::str::FromStr for AssetCode12 { impl core::fmt::Display for AssetCode12 { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - if let Some(last_idx) = self.0.iter().rposition(|c| *c != 0) { - for b in escape_bytes::Escape::new(&self.0[..=last_idx]) { - write!(f, "{}", b as char)?; - } + // AssetCode12's are always rendered as at least 5 characters, because + // any asset code shorter than 5 characters is an AssetCode4. + // AssetCode12 contains a fixed length 12-byte array, and the constant + // and slices in this function never operate out-of-bounds because of + // that. + const MIN_LENGTH: usize = 5; + let len = MIN_LENGTH + + self + .0 + .iter() + .skip(MIN_LENGTH) + .rposition(|c| *c != 0) + .map_or(0, |last_idx| last_idx + 1); + for b in escape_bytes::Escape::new(&self.0[..len]) { + write!(f, "{}", b as char)?; } Ok(()) } @@ -330,6 +342,29 @@ impl core::fmt::Display for AssetCode { } } +impl core::str::FromStr for Asset { + type Err = Error; + + fn from_str(value: &str) -> Result { + if value == "native" { + return Ok(Asset::Native); + } + let mut iter = value.splitn(2, ':'); + let (Some(code), Some(issuer), None) = (iter.next(), iter.next(), iter.next()) else { + return Err(Error::Invalid); + }; + let issuer = issuer.parse()?; + Ok(match code.parse()? { + AssetCode::CreditAlphanum4(asset_code) => { + Asset::CreditAlphanum4(AlphaNum4 { asset_code, issuer }) + } + AssetCode::CreditAlphanum12(asset_code) => { + Asset::CreditAlphanum12(AlphaNum12 { asset_code, issuer }) + } + }) + } +} + impl core::str::FromStr for ClaimableBalanceId { type Err = Error; fn from_str(s: &str) -> core::result::Result { diff --git a/src/next/transaction_conversions.rs b/src/next/transaction_conversions.rs index a821a51f..b680fa54 100644 --- a/src/next/transaction_conversions.rs +++ b/src/next/transaction_conversions.rs @@ -3,6 +3,52 @@ use super::{ TransactionV1Envelope, VecM, }; +#[cfg(feature = "alloc")] +use super::{Error, Memo, MuxedAccount, Operation, Preconditions, SequenceNumber, TransactionExt}; +#[cfg(feature = "sha2")] +use super::{ + Hash, Limits, TransactionSignaturePayload, TransactionSignaturePayloadTaggedTransaction, + WriteXdr, +}; + +impl Transaction { + #[cfg(feature = "alloc")] + pub fn new_tx( + source_account: impl Into, + fee: u32, + seq_num: impl Into, + operation: Operation, + ) -> Transaction { + Transaction { + source_account: source_account.into(), + fee, + seq_num: seq_num.into(), + cond: Preconditions::None, + memo: Memo::None, + operations: [operation].try_into().unwrap(), + ext: TransactionExt::V0, + } + } + #[cfg(feature = "alloc")] + pub fn add_operation(mut self, operation: Operation) -> Result { + let mut ops = self.operations.to_vec(); + ops.push(operation); + self.operations = ops.try_into().map_err(|_| Error::Invalid)?; + Ok(self) + } + + #[cfg(feature = "sha2")] + pub fn hash(&self, network_passphrase: &str) -> Result { + let signature_payload = TransactionSignaturePayload { + network_id: Hash::hash_bytes(network_passphrase), + tagged_transaction: TransactionSignaturePayloadTaggedTransaction::Tx(self.clone()), + }; + signature_payload + .to_xdr(Limits::none()) + .map(Hash::hash_bytes) + } +} + impl From for TransactionEnvelope { fn from(tx: Transaction) -> Self { TransactionEnvelope::Tx(TransactionV1Envelope { diff --git a/tests/account_conversions.rs b/tests/account_conversions.rs index cab94738..9de7fda6 100644 --- a/tests/account_conversions.rs +++ b/tests/account_conversions.rs @@ -28,7 +28,7 @@ fn from_public_key_to_muxed_account() { #[test] fn from_muxed_account_ed_to_account_id() { let muxed_account: MuxedAccount = MuxedAccount::Ed25519(Uint256([1u8; 32])); - let account_id = muxed_account.account_id(); + let account_id: AccountId = muxed_account.into(); assert_eq!( account_id, AccountId(PublicKey::PublicKeyTypeEd25519(Uint256([1u8; 32]))) @@ -41,7 +41,7 @@ fn from_muxed_account_med_to_account_id() { id: 2, ed25519: Uint256([1u8; 32]), }); - let account_id = muxed_account.account_id(); + let account_id: AccountId = muxed_account.into(); assert_eq!( account_id, AccountId(PublicKey::PublicKeyTypeEd25519(Uint256([1u8; 32]))) diff --git a/tests/hash.rs b/tests/hash.rs new file mode 100644 index 00000000..ae515c59 --- /dev/null +++ b/tests/hash.rs @@ -0,0 +1,9 @@ +#![cfg(all(feature = "curr", feature = "hex"))] +use stellar_xdr::curr::Hash; + +#[test] +fn hash_padding() { + let padded = "0000000000000000000000000000000011111111111111111111111111111111"; + let non_padded = "11111111111111111111111111111111"; + assert_eq!(Hash::from_hex(padded), Hash::from_hex(non_padded)); +} diff --git a/tests/num_conversions.rs b/tests/num_conversions.rs new file mode 100644 index 00000000..0c8291f0 --- /dev/null +++ b/tests/num_conversions.rs @@ -0,0 +1,44 @@ +#![cfg(all( + any(feature = "curr", feature = "next"), + not(all(feature = "curr", feature = "next")) +))] +#![cfg(feature = "std")] + +#[cfg(feature = "curr")] +use stellar_xdr::curr as stellar_xdr; +#[cfg(feature = "next")] +use stellar_xdr::next as stellar_xdr; + +use stellar_xdr::{Int128Parts, UInt128Parts, UInt256Parts}; + +#[test] +fn round_trip_u128() { + let u128_val = 0x1234567890abcdef1234567890abcdefu128; + let xdr_val: UInt128Parts = u128_val.into(); + let u128_val2: u128 = xdr_val.into(); + assert_eq!(u128_val, u128_val2); +} + +#[test] +fn round_trip_i128() { + let i128_val = 0x1234567890abcdef1234567890abcdefi128; + let xdr_val: Int128Parts = i128_val.into(); + let i128_val2: i128 = xdr_val.into(); + assert_eq!(i128_val, i128_val2); +} + +#[test] +fn round_trip_u256() { + let (hi, lo) = (0x1234567890abcdefu128, 0x1234567890abcdefu128); + let xdr_val: UInt256Parts = (hi, lo).into(); + let (hi2, lo2): (u128, u128) = xdr_val.into(); + assert_eq!((hi, lo), (hi2, lo2)); +} + +#[test] +fn round_trip_i256() { + let (hi, lo) = (0x1234567890abcdefi128, 0x1234567890abcdefi128); + let xdr_val: Int256Parts = (hi, lo).into(); + let (hi2, lo2): (i128, i128) = xdr_val.into(); + assert_eq!((hi, lo), (hi2, lo2)); +}