From bb76f797691c7e3c6fa73005ef1d45b1525ab8d1 Mon Sep 17 00:00:00 2001 From: cindytrang Date: Sun, 13 Oct 2024 01:29:08 +0100 Subject: [PATCH 1/2] Added the contracts env --- .gitignore | 6 + Cargo.lock | 1510 +++++++++++++++++++++++++++++++++++ Cargo.toml | 23 + contracts/Cargo.toml | 18 + contracts/README | 22 + contracts/src/base64_url.rs | 73 ++ contracts/src/lib.rs | 116 +++ contracts/src/test.rs | 116 +++ dapp/package.json | 7 + dapp/pnpm-lock.yaml | 346 ++++++++ dapp/src/App.tsx | 2 + dapp/src/definitions.ts | 8 + dapp/src/index.ts | 10 + dapp/src/lib/deploy.ts | 69 ++ dapp/src/lib/get_votes.ts | 50 ++ dapp/src/lib/vote_build.ts | 49 ++ dapp/src/lib/vote_send.ts | 54 ++ dapp/src/lib/webauthn.ts | 259 ++++++ dapp/src/pages/Auth.tsx | 348 ++++++++ dapp/src/web.ts | 48 ++ 20 files changed, 3134 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 contracts/Cargo.toml create mode 100644 contracts/README create mode 100644 contracts/src/base64_url.rs create mode 100644 contracts/src/lib.rs create mode 100644 contracts/src/test.rs create mode 100644 dapp/src/definitions.ts create mode 100644 dapp/src/index.ts create mode 100644 dapp/src/lib/deploy.ts create mode 100644 dapp/src/lib/get_votes.ts create mode 100644 dapp/src/lib/vote_build.ts create mode 100644 dapp/src/lib/vote_send.ts create mode 100644 dapp/src/lib/webauthn.ts create mode 100644 dapp/src/pages/Auth.tsx create mode 100644 dapp/src/web.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57abcc5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Rust's output directory +target + +# Local Soroban settings +.soroban +.DS_Store diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..c0d04da --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1510 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base32" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[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.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes-lit" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0adabf37211a5276e46335feabcbb1530c95eb3fdf85f324c7db942770aa025d" +dependencies = [ + "num-bigint", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cc" +version = "1.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "contracts" +version = "0.0.0" +dependencies = [ + "serde", + "serde-json-core", + "soroban-sdk", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crate-git-revision" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c521bf1f43d31ed2f73441775ed31935d77901cb3451e44b38a1c1612fcbaf98" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctor" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[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.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bfcf67fea2815c2fc3b90873fae90957be12ff417335dfadc7f52927feb03b2" + +[[package]] +name = "ethnum" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fnv" +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", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[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 = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "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", +] + +[[package]] +name = "indexmap-nostd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9e1ab533c0bc414c34920ec7e5f097101d126ed5eac1a1aac711222e0bbb33" +dependencies = [ + "ryu", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.6.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[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 = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "soroban-builtin-sdk-macros" +version = "21.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f57a68ef8777e28e274de0f3a88ad9a5a41d9a2eb461b4dd800b086f0e83b80" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "soroban-env-common" +version = "21.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1c89463835fe6da996318156d39f424b4f167c725ec692e5a7a2d4e694b3d" +dependencies = [ + "arbitrary", + "crate-git-revision", + "ethnum", + "num-derive", + "num-traits", + "serde", + "soroban-env-macros", + "soroban-wasmi", + "static_assertions", + "stellar-xdr", + "wasmparser", +] + +[[package]] +name = "soroban-env-guest" +version = "21.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bfb2536811045d5cd0c656a324cbe9ce4467eb734c7946b74410d90dea5d0ce" +dependencies = [ + "soroban-env-common", + "static_assertions", +] + +[[package]] +name = "soroban-env-host" +version = "21.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b7a32c28f281c423189f1298960194f0e0fc4eeb72378028171e556d8cd6160" +dependencies = [ + "backtrace", + "curve25519-dalek", + "ecdsa", + "ed25519-dalek", + "elliptic-curve", + "generic-array", + "getrandom", + "hex-literal", + "hmac", + "k256", + "num-derive", + "num-integer", + "num-traits", + "p256", + "rand", + "rand_chacha", + "sec1", + "sha2", + "sha3", + "soroban-builtin-sdk-macros", + "soroban-env-common", + "soroban-wasmi", + "static_assertions", + "stellar-strkey", + "wasmparser", +] + +[[package]] +name = "soroban-env-macros" +version = "21.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "242926fe5e0d922f12d3796cd7cd02dd824e5ef1caa088f45fce20b618309f64" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "serde", + "serde_json", + "stellar-xdr", + "syn", +] + +[[package]] +name = "soroban-ledger-snapshot" +version = "21.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956476365ff3f9bf429ff23fa11ac75798347a2bfc3c9e5e12638dbe3a6b17a8" +dependencies = [ + "serde", + "serde_json", + "serde_with", + "soroban-env-common", + "soroban-env-host", + "thiserror", +] + +[[package]] +name = "soroban-sdk" +version = "21.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7767472f00a4053e86d5c37b3c814a6bc01c9230004713328d73d2a3444e72e" +dependencies = [ + "arbitrary", + "bytes-lit", + "ctor", + "ed25519-dalek", + "rand", + "serde", + "serde_json", + "soroban-env-guest", + "soroban-env-host", + "soroban-ledger-snapshot", + "soroban-sdk-macros", + "stellar-strkey", +] + +[[package]] +name = "soroban-sdk-macros" +version = "21.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8cf8fa10f3ad62509ff7b25cd696fb837da692c40264d1abb393e117aad75c" +dependencies = [ + "crate-git-revision", + "darling", + "itertools", + "proc-macro2", + "quote", + "rustc_version", + "sha2", + "soroban-env-common", + "soroban-spec", + "soroban-spec-rust", + "stellar-xdr", + "syn", +] + +[[package]] +name = "soroban-spec" +version = "21.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12d306f61ef5c1247dca1562e04cc74b6e3adf107631c168b2ce0d5f1cf1fa13" +dependencies = [ + "base64 0.13.1", + "stellar-xdr", + "thiserror", + "wasmparser", +] + +[[package]] +name = "soroban-spec-rust" +version = "21.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bed06e0f622fb878fc439643f2fd86163223ac33a468beeea96e5d33f79b08b3" +dependencies = [ + "prettyplease", + "proc-macro2", + "quote", + "sha2", + "soroban-spec", + "stellar-xdr", + "syn", + "thiserror", +] + +[[package]] +name = "soroban-wasmi" +version = "0.31.1-soroban.20.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710403de32d0e0c35375518cb995d4fc056d0d48966f2e56ea471b8cb8fc9719" +dependencies = [ + "smallvec", + "spin", + "wasmi_arena", + "wasmi_core", + "wasmparser-nostd", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stellar-strkey" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12d2bf45e114117ea91d820a846fd1afbe3ba7d717988fee094ce8227a3bf8bd" +dependencies = [ + "base32", + "crate-git-revision", + "thiserror", +] + +[[package]] +name = "stellar-xdr" +version = "21.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2675a71212ed39a806e415b0dbf4702879ff288ec7f5ee996dda42a135512b50" +dependencies = [ + "arbitrary", + "base64 0.13.1", + "crate-git-revision", + "escape-bytes", + "hex", + "serde", + "serde_with", + "stellar-strkey", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "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.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "wasmi_arena" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "104a7f73be44570cac297b3035d76b169d6599637631cf37a1703326a0727073" + +[[package]] +name = "wasmi_core" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf1a7db34bff95b85c261002720c00c3a6168256dcb93041d3fa2054d19856a" +dependencies = [ + "downcast-rs", + "libm", + "num-traits", + "paste", +] + +[[package]] +name = "wasmparser" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50" +dependencies = [ + "indexmap 2.6.0", + "semver", +] + +[[package]] +name = "wasmparser-nostd" +version = "0.100.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5a015fe95f3504a94bb1462c717aae75253e39b9dd6c3fb1062c934535c64aa" +dependencies = [ + "indexmap-nostd", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +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 = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +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 = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b1c4826 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,23 @@ +[workspace] +resolver = "2" +members = [ + "contracts", +] + +[workspace.dependencies] +soroban-sdk = "21.0.0" + +[profile.release] +opt-level = "z" +overflow-checks = true +debug = 0 +strip = "symbols" +debug-assertions = false +panic = "abort" +codegen-units = 1 +lto = true + +# For more information about this profile see https://soroban.stellar.org/docs/basic-tutorials/logging#cargotoml-profile +[profile.release-with-logs] +inherits = "release" +debug-assertions = true diff --git a/contracts/Cargo.toml b/contracts/Cargo.toml new file mode 100644 index 0000000..6c2d441 --- /dev/null +++ b/contracts/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "contracts" +version = "0.0.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] +doctest = false + +[dependencies] +soroban-sdk = { workspace = true } +serde = { version = "1", default-features = false, features = ["derive"] } +serde-json-core = { version = "0.5.1", default-features = false } + + +[dev-dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } diff --git a/contracts/README b/contracts/README new file mode 100644 index 0000000..40469fe --- /dev/null +++ b/contracts/README @@ -0,0 +1,22 @@ +stellar keys generate --global alice --network testnet + +stellar keys address admin (to see the key): +GCI3JTWP25EPIRNFVHBZPK2JYISMMWWBWGXQS4PJSBBEMYX4BYPK2CPO + +stellar contract invoke \ + --id CBNO2EP5OLDLBSQ6ZBVUY4U4VMFTP7SMTGVQ2FMSNMEY5AUZEJKQYYFK \ + --source admin \ + --network testnet \ + -- \ + init \ + --pk eb58656ce37f7910da94506be0db06befdce032b1605d0f6fc2ccd2e79322d0a + + stellar contract deploy \ + --wasm target/wasm32-unknown-unknown/release/contracts.wasm \ + --source admin \ + --network testnet + +stellar network add \ + --global testnet \ + --rpc-url https://soroban-testnet.stellar.org:443 \ + --network-passphrase "Test SDF Network ; September 2015" diff --git a/contracts/src/base64_url.rs b/contracts/src/base64_url.rs new file mode 100644 index 0000000..e511ae2 --- /dev/null +++ b/contracts/src/base64_url.rs @@ -0,0 +1,73 @@ +// Ported from https://github.com/golang/go/blob/26b5783b72376acd0386f78295e678b9a6bff30e/src/encoding/base64/base64.go#L53-L192 +// +// Modifications: +// * Removed logic supporting padding. +// * Hardcoded the Base64 URL alphabet. +// * Use a fixed length pre-allocated destination. +// * Ported to Rust. +// +// Original Copyright notice: +// +// Copyright (c) 2009 The Go Authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +const ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +pub fn encode(dst: &mut [u8], src: &[u8]) { + let mut di: usize = 0; + let mut si: usize = 0; + let n = (src.len() / 3) * 3; + + while si < n { + let val = (src[si] as usize) << 16 | (src[si + 1] as usize) << 8 | (src[si + 2] as usize); + dst[di] = ALPHABET[val >> 18 & 0x3F]; + dst[di + 1] = ALPHABET[val >> 12 & 0x3F]; + dst[di + 2] = ALPHABET[val >> 6 & 0x3F]; + dst[di + 3] = ALPHABET[val & 0x3F]; + si += 3; + di += 4; + } + + let remain = src.len() - si; + + if remain == 0 { + return; + } + + let mut val = (src[si] as usize) << 16; + + if remain == 2 { + val |= (src[si + 1] as usize) << 8; + } + + dst[di] = ALPHABET[val >> 18 & 0x3F]; + dst[di + 1] = ALPHABET[val >> 12 & 0x3F]; + + if remain == 2 { + dst[di + 2] = ALPHABET[val >> 6 & 0x3F]; + } +} \ No newline at end of file diff --git a/contracts/src/lib.rs b/contracts/src/lib.rs new file mode 100644 index 0000000..73794fe --- /dev/null +++ b/contracts/src/lib.rs @@ -0,0 +1,116 @@ +#![no_std] +use soroban_sdk::{ + auth::{Context, CustomAccountInterface}, + contract, contracterror, contractimpl, contracttype, + crypto::Hash, + symbol_short, Bytes, BytesN, Env, Symbol, Vec, +}; + +mod base64_url; + +#[contract] +pub struct Contract; + +#[contracterror] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum Error { + NotInited = 1, + AlreadyInited = 2, + ClientDataJsonChallengeIncorrect = 3, + Secp256r1PublicKeyParse = 4, + Secp256r1SignatureParse = 5, + Secp256r1VerifyFailed = 6, + JsonParseError = 7, +} + +const STORAGE_KEY_PK: Symbol = symbol_short!("pk"); + +#[contractimpl] +impl Contract { + pub fn extend_ttl(env: Env) { + let max_ttl = env.storage().max_ttl(); + let contract_address = env.current_contract_address(); + + env.storage().instance().extend_ttl(max_ttl, max_ttl); + env.deployer() + .extend_ttl(contract_address.clone(), max_ttl, max_ttl); + env.deployer() + .extend_ttl_for_code(contract_address.clone(), max_ttl, max_ttl); + env.deployer() + .extend_ttl_for_contract_instance(contract_address.clone(), max_ttl, max_ttl); + } + pub fn init(env: Env, pk: BytesN<65>) -> Result<(), Error> { + if env.storage().instance().has(&STORAGE_KEY_PK) { + return Err(Error::AlreadyInited); + } + + env.storage().instance().set(&STORAGE_KEY_PK, &pk); + + Self::extend_ttl(env); + + Ok(()) + } +} + +#[contracttype] +pub struct Signature { + pub authenticator_data: Bytes, + pub client_data_json: Bytes, + pub signature: BytesN<64>, +} + +#[derive(serde::Deserialize)] +struct ClientDataJson<'a> { + challenge: &'a str, +} + +#[contractimpl] +impl CustomAccountInterface for Contract { + type Error = Error; + type Signature = Signature; + + #[allow(non_snake_case)] + fn __check_auth( + env: Env, + signature_payload: Hash<32>, + signature: Signature, + _auth_contexts: Vec, + ) -> Result<(), Error> { + // Verify that the public key produced the signature. + let pk = env + .storage() + .instance() + .get(&STORAGE_KEY_PK) + .ok_or(Error::NotInited)?; + + let mut payload = Bytes::new(&env); + + payload.append(&signature.authenticator_data); + payload.extend_from_array(&env.crypto().sha256(&signature.client_data_json).to_array()); + let payload = env.crypto().sha256(&payload); + + env.crypto() + .secp256r1_verify(&pk, &payload, &signature.signature); + + // Parse the client data JSON, extracting the base64 url encoded + // challenge. + let client_data_json = signature.client_data_json.to_buffer::<1024>(); + let client_data_json = client_data_json.as_slice(); + let (client_data, _): (ClientDataJson, _) = + serde_json_core::de::from_slice(client_data_json).map_err(|_| Error::JsonParseError)?; + + // Build what the base64 url challenge is expected. + let mut expected_challenge = *b"___________________________________________"; + base64_url::encode(&mut expected_challenge, &signature_payload.to_array()); + + // Check that the challenge inside the client data JSON that was signed + // is identical to the expected challenge. + if client_data.challenge.as_bytes() != expected_challenge { + return Err(Error::ClientDataJsonChallengeIncorrect); + } + + Self::extend_ttl(env); + + Ok(()) + } +} \ No newline at end of file diff --git a/contracts/src/test.rs b/contracts/src/test.rs new file mode 100644 index 0000000..78b855a --- /dev/null +++ b/contracts/src/test.rs @@ -0,0 +1,116 @@ +#![cfg(test)] +extern crate std; + +use super::*; +use soroban_sdk::{testutils::EnvExt, BytesN, Bytes, Symbol, Env, Vec}; + +#[test] +fn test_init_success() { + let env = Env::default(); + let contract = Contract; + + // Sample public key for initialization (65 bytes) + let public_key = BytesN::<65>::from_array(&env, &[1u8; 65]); + + // Call init function and check for successful initialization + let result = contract.init(env.clone(), public_key.clone()); + assert!(result.is_ok()); + + // Ensure the public key is stored in the contract's storage + let stored_pk: BytesN<65> = env.storage().instance().get(&STORAGE_KEY_PK).unwrap(); + assert_eq!(stored_pk, public_key); +} + +#[test] +fn test_init_already_inited() { + let env = Env::default(); + let contract = Contract; + + // Initialize the contract with a public key + let public_key = BytesN::<65>::from_array(&env, &[1u8; 65]); + contract.init(env.clone(), public_key.clone()).unwrap(); + + // Try initializing again and check for an error + let result = contract.init(env, public_key); + assert_eq!(result, Err(Error::AlreadyInited)); +} + +#[test] +fn test_extend_ttl() { + let env = Env::default(); + let contract = Contract; + + // Sample public key for initialization + let public_key = BytesN::<65>::from_array(&env, &[1u8; 65]); + + // Call init function and ensure TTL is extended + contract.init(env.clone(), public_key).unwrap(); + + // Check that TTL was extended correctly + let contract_address = env.current_contract_address(); + assert!(env.storage().instance().has(&STORAGE_KEY_PK)); + assert!(env.storage().instance().get_ttl().is_some()); + assert!(env.deployer().get_ttl(contract_address.clone()).is_some()); +} + +#[test] +fn test_check_auth_success() { + let env = Env::default(); + let contract = Contract; + + // Initialize the contract with a public key + let public_key = BytesN::<65>::from_array(&env, &[1u8; 65]); + contract.init(env.clone(), public_key.clone()).unwrap(); + + // Prepare mock signature data for verification + let signature_payload = Hash::from_array(&[1u8; 32]); + let authenticator_data = Bytes::from_array(&env, &[1u8; 10]); + let client_data_json = Bytes::from_array(&env, &[1u8; 10]); + let signature = BytesN::<64>::from_array(&env, &[1u8; 64]); + + let signature_data = Signature { + authenticator_data, + client_data_json, + signature, + }; + + // Verify the signature (mock the crypto part for the test) + let result = contract.__check_auth( + env.clone(), + signature_payload.clone(), + signature_data, + Vec::new(&env), + ); + assert!(result.is_ok()); +} + +#[test] +fn test_check_auth_invalid_signature() { + let env = Env::default(); + let contract = Contract; + + // Initialize the contract with a public key + let public_key = BytesN::<65>::from_array(&env, &[1u8; 65]); + contract.init(env.clone(), public_key.clone()).unwrap(); + + // Prepare mock signature data with an incorrect signature + let signature_payload = Hash::from_array(&[1u8; 32]); + let authenticator_data = Bytes::from_array(&env, &[1u8; 10]); + let client_data_json = Bytes::from_array(&env, &[1u8; 10]); + let signature = BytesN::<64>::from_array(&env, &[2u8; 64]); // Different signature + + let signature_data = Signature { + authenticator_data, + client_data_json, + signature, + }; + + // Attempt to verify the invalid signature + let result = contract.__check_auth( + env.clone(), + signature_payload.clone(), + signature_data, + Vec::new(&env), + ); + assert_eq!(result, Err(Error::Secp256r1VerifyFailed)); +} diff --git a/dapp/package.json b/dapp/package.json index 4db266c..cce9f06 100644 --- a/dapp/package.json +++ b/dapp/package.json @@ -10,6 +10,8 @@ "preview": "vite preview" }, "dependencies": { + "@capacitor/core": "^6.1.2", + "@capacitor/share": "^6.0.2", "@creit.tech/stellar-wallets-kit": "^1.2.3", "@radix-ui/react-checkbox": "^1.1.2", "@radix-ui/react-icons": "^1.3.0", @@ -18,6 +20,10 @@ "@radix-ui/react-select": "^2.1.2", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-toast": "^1.2.2", + "@stellar/stellar-sdk": "^12.3.0", + "base64url": "^3.0.1", + "bigint-conversion": "^2.4.3", + "cbor-x": "^1.6.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "framer-motion": "^11.11.8", @@ -26,6 +32,7 @@ "react-dom": "^18.3.1", "react-responsive": "^10.0.0", "react-router-dom": "^6.27.0", + "stellar-sdk": "^12.3.0", "tailwind-merge": "^2.5.3", "tailwindcss-animate": "^1.0.7" }, diff --git a/dapp/pnpm-lock.yaml b/dapp/pnpm-lock.yaml index 5bd18d8..924053d 100644 --- a/dapp/pnpm-lock.yaml +++ b/dapp/pnpm-lock.yaml @@ -8,6 +8,12 @@ importers: .: dependencies: + '@capacitor/core': + specifier: ^6.1.2 + version: 6.1.2 + '@capacitor/share': + specifier: ^6.0.2 + version: 6.0.2(@capacitor/core@6.1.2) '@creit.tech/stellar-wallets-kit': specifier: ^1.2.3 version: 1.2.3(@types/react@18.3.11)(react@18.3.1) @@ -32,6 +38,18 @@ importers: '@radix-ui/react-toast': specifier: ^1.2.2 version: 1.2.2(@types/react-dom@18.3.0)(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@stellar/stellar-sdk': + specifier: ^12.3.0 + version: 12.3.0 + base64url: + specifier: ^3.0.1 + version: 3.0.1 + bigint-conversion: + specifier: ^2.4.3 + version: 2.4.3 + cbor-x: + specifier: ^1.6.0 + version: 1.6.0 class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -56,6 +74,9 @@ importers: react-router-dom: specifier: ^6.27.0 version: 6.27.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + stellar-sdk: + specifier: ^12.3.0 + version: 12.3.0 tailwind-merge: specifier: ^2.5.3 version: 2.5.3 @@ -250,6 +271,44 @@ packages: cpu: [x64] os: [win32] + '@capacitor/core@6.1.2': + resolution: {integrity: sha512-xFy1/4qLFLp5WCIzIhtwUuVNNoz36+V7/BzHmLqgVJcvotc4MMjswW/TshnPQaLLujEOaLkA4h8ZJ0uoK3ImGg==} + + '@capacitor/share@6.0.2': + resolution: {integrity: sha512-qQIeyjzFB1VgP4ojyNg2O98TCigDWLKZ5melVMSVeDO0YQov5OeammsVgaCGSzvYBPSgyOwX41QvcDWG4yHN1A==} + peerDependencies: + '@capacitor/core': ^6.0.0 + + '@cbor-extract/cbor-extract-darwin-arm64@2.2.0': + resolution: {integrity: sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==} + cpu: [arm64] + os: [darwin] + + '@cbor-extract/cbor-extract-darwin-x64@2.2.0': + resolution: {integrity: sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==} + cpu: [x64] + os: [darwin] + + '@cbor-extract/cbor-extract-linux-arm64@2.2.0': + resolution: {integrity: sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==} + cpu: [arm64] + os: [linux] + + '@cbor-extract/cbor-extract-linux-arm@2.2.0': + resolution: {integrity: sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==} + cpu: [arm] + os: [linux] + + '@cbor-extract/cbor-extract-linux-x64@2.2.0': + resolution: {integrity: sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==} + cpu: [x64] + os: [linux] + + '@cbor-extract/cbor-extract-win32-x64@2.2.0': + resolution: {integrity: sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==} + cpu: [x64] + os: [win32] + '@creit.tech/stellar-wallets-kit@1.2.3': resolution: {integrity: sha512-AM1fL/cQkI0i+lefJlViOPR4uxZrPDImbF+eCYST7FEIWYZrPsd/Mtne5qGVJDC6Umzdg9HqJt7CSFZTUJ2b3A==} engines: {node: '>=16'} @@ -258,6 +317,11 @@ packages: resolution: {integrity: sha512-pByi0bTAWd2ZdolVtkXcAU1DYTtz/cJc/IkRUz9x9/1NsFVyrM4UxE8tHgVZ3mwrJ4josoDwYP957ynQw195YQ==} engines: {node: '>=16'} + '@darkedges/capacitor-native-webauthn@0.0.4': + resolution: {integrity: sha512-/dbNpjKyh3Ofh2oXheDgi4YrXPlO6/wKHtCOb+bRYLMirDC4oAuJ4kgIDoKygKkEN2BnU2hypCPDIC53omcbOg==} + peerDependencies: + '@capacitor/core': ^5.0.0 + '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -436,6 +500,9 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@juanelas/base64@1.1.5': + resolution: {integrity: sha512-mjAF27LzwfYobdwqnxZgeucbKT5wRRNvILg3h5OvCWK+3F7mw/A1tnjHnNiTYtLmTvT/bM1jA5AX7eQawDGs1w==} + '@lit-labs/ssr-dom-shim@1.2.1': resolution: {integrity: sha512-wx4aBmgeGvFmOKucFKY+8VFJSYZxs9poN3SDNQFF6lT6NrQUnHiPB2PWz2sc4ieEcAaYYzN+1uWahEeTq2aRIQ==} @@ -1009,6 +1076,12 @@ packages: cpu: [x64] os: [win32] + '@simplewebauthn/browser@9.0.1': + resolution: {integrity: sha512-wD2WpbkaEP4170s13/HUxPcAV5y4ZXaKo1TfNklS5zDefPinIgXOpgz1kpEvobAsaLPa2KeH7AKKX/od1mrBJw==} + + '@simplewebauthn/types@9.0.1': + resolution: {integrity: sha512-tGSRP1QvsAvsJmnOlRQyw/mvK9gnPtjEc5fg2+m8n+QUa+D7rvrKkOYyfpy42GTs90X3RDOnqJgfHt+qO67/+w==} + '@stablelib/aead@1.0.1': resolution: {integrity: sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==} @@ -1066,6 +1139,15 @@ packages: '@stellar/freighter-api@3.0.0': resolution: {integrity: sha512-AI1AeHnCPLMcM8d6182FScOJjCFd1tLZcNuu5M10NmtuLfNzavw+f991dWBoz6h41mOKjauIaojR+7VfU2nULg==} + '@stellar/js-xdr@3.1.2': + resolution: {integrity: sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==} + + '@stellar/stellar-base@12.1.1': + resolution: {integrity: sha512-gOBSOFDepihslcInlqnxKZdIW9dMUO1tpOm3AtJR33K2OvpXG6SaVHCzAmCFArcCqI9zXTEiSoh70T48TmiHJA==} + + '@stellar/stellar-sdk@12.3.0': + resolution: {integrity: sha512-F2DYFop/M5ffXF0lvV5Ezjk+VWNKg0QDX8gNhwehVU3y5LYA3WAY6VcCarMGPaG9Wdgoeh1IXXzOautpqpsltw==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1215,6 +1297,9 @@ packages: resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} engines: {node: '>=10'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + atomic-sleep@1.0.0: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} @@ -1226,12 +1311,29 @@ packages: peerDependencies: postcss: ^8.1.0 + axios@1.7.7: + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base32.js@0.1.0: + resolution: {integrity: sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==} + engines: {node: '>=0.12.0'} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + base64url@3.0.1: + resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==} + engines: {node: '>=6.0.0'} + + bigint-conversion@2.4.3: + resolution: {integrity: sha512-eM76IXlhXQD6HAoE6A7QLQ3jdC04EJdjH3zrlU1Jtt4/jj+O/pMGjGR5FY8/55FOIBsK25kly0RoG4GA4iKdvg==} + + bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -1265,6 +1367,13 @@ packages: caniuse-lite@1.0.30001666: resolution: {integrity: sha512-gD14ICmoV5ZZM1OdzPWmpx+q4GyefaK06zi8hmfHV5xe4/2nOQX3+Dw5o+fSqOws2xVwL9j+anOPFwHzdEdV4g==} + cbor-extract@2.2.0: + resolution: {integrity: sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==} + hasBin: true + + cbor-x@1.6.0: + resolution: {integrity: sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -1307,6 +1416,10 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -1365,6 +1478,10 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + destr@2.0.3: resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} @@ -1376,6 +1493,10 @@ packages: engines: {node: '>=0.10'} hasBin: true + detect-libc@2.0.3: + resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + engines: {node: '>=8'} + detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} @@ -1426,6 +1547,10 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + eventsource@2.0.2: + resolution: {integrity: sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==} + engines: {node: '>=12.0.0'} + execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} @@ -1453,10 +1578,23 @@ packages: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + foreground-child@3.3.0: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -1705,6 +1843,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -1765,6 +1911,14 @@ packages: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} + node-gyp-build-optional-packages@5.1.1: + resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==} + hasBin: true + + node-gyp-build@4.8.2: + resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==} + hasBin: true + node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} @@ -1923,6 +2077,9 @@ packages: proxy-compare@2.5.1: resolution: {integrity: sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + qrcode@1.5.3: resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} engines: {node: '>=10.13.0'} @@ -1941,6 +2098,9 @@ packages: radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: @@ -2064,8 +2224,14 @@ packages: set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} +<<<<<<< HEAD shallow-equal@3.1.0: resolution: {integrity: sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg==} +======= + sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true +>>>>>>> ed2751b (Added the contracts env) shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -2079,6 +2245,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + sodium-native@4.2.1: + resolution: {integrity: sha512-48X3PfRLW+f0fgb3J7f7mkZ9eBKcGR/bD5mdXXLAx4RWwKUe3095yPQgiUUQTfh8Q29JzwhSQATitQDBIozN/w==} + sonic-boom@2.8.0: resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==} @@ -2104,6 +2273,10 @@ packages: std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + stellar-sdk@12.3.0: + resolution: {integrity: sha512-3z7umyuBAHN+vm3zLTKqj7P/bErBFnjrwoanBsNyBHaoek9krUgufNupQSMK67B1p0E2NKD1Z6gYPuZiPfJ2qQ==} + deprecated: ⚠️ This package has moved to @stellar/stellar-sdk! 🚚 + stream-shift@1.0.3: resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} @@ -2187,6 +2360,9 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toml@3.0.0: + resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -2285,6 +2461,9 @@ packages: uqr@0.1.2: resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} + urijs@1.19.11: + resolution: {integrity: sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==} + use-callback-ref@1.3.2: resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} engines: {node: '>=10'} @@ -2586,6 +2765,32 @@ snapshots: '@biomejs/cli-win32-x64@1.9.3': optional: true + '@capacitor/core@6.1.2': + dependencies: + tslib: 2.7.0 + + '@capacitor/share@6.0.2(@capacitor/core@6.1.2)': + dependencies: + '@capacitor/core': 6.1.2 + + '@cbor-extract/cbor-extract-darwin-arm64@2.2.0': + optional: true + + '@cbor-extract/cbor-extract-darwin-x64@2.2.0': + optional: true + + '@cbor-extract/cbor-extract-linux-arm64@2.2.0': + optional: true + + '@cbor-extract/cbor-extract-linux-arm@2.2.0': + optional: true + + '@cbor-extract/cbor-extract-linux-x64@2.2.0': + optional: true + + '@cbor-extract/cbor-extract-win32-x64@2.2.0': + optional: true + '@creit.tech/stellar-wallets-kit@1.2.3(@types/react@18.3.11)(react@18.3.1)': dependencies: '@albedo-link/intent': 0.12.0 @@ -2627,6 +2832,11 @@ snapshots: tweetnacl: 1.0.3 tweetnacl-util: 0.15.1 + '@darkedges/capacitor-native-webauthn@0.0.4(@capacitor/core@6.1.2)': + dependencies: + '@capacitor/core': 6.1.2 + '@simplewebauthn/browser': 9.0.1 + '@esbuild/aix-ppc64@0.21.5': optional: true @@ -2745,6 +2955,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@juanelas/base64@1.1.5': {} + '@lit-labs/ssr-dom-shim@1.2.1': {} '@lit/reactive-element@1.6.3': @@ -3253,6 +3465,12 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.24.0': optional: true + '@simplewebauthn/browser@9.0.1': + dependencies: + '@simplewebauthn/types': 9.0.1 + + '@simplewebauthn/types@9.0.1': {} + '@stablelib/aead@1.0.1': {} '@stablelib/binary@1.0.1': @@ -3335,6 +3553,31 @@ snapshots: '@stellar/freighter-api@3.0.0': {} + '@stellar/js-xdr@3.1.2': {} + + '@stellar/stellar-base@12.1.1': + dependencies: + '@stellar/js-xdr': 3.1.2 + base32.js: 0.1.0 + bignumber.js: 9.1.2 + buffer: 6.0.3 + sha.js: 2.4.11 + tweetnacl: 1.0.3 + optionalDependencies: + sodium-native: 4.2.1 + + '@stellar/stellar-sdk@12.3.0': + dependencies: + '@stellar/stellar-base': 12.1.1 + axios: 1.7.7 + bignumber.js: 9.1.2 + eventsource: 2.0.2 + randombytes: 2.1.0 + toml: 3.0.0 + urijs: 1.19.11 + transitivePeerDependencies: + - debug + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.25.7 @@ -3661,6 +3904,8 @@ snapshots: dependencies: tslib: 2.7.0 + asynckit@0.4.0: {} + atomic-sleep@1.0.0: {} autoprefixer@10.4.20(postcss@8.4.47): @@ -3673,10 +3918,28 @@ snapshots: postcss: 8.4.47 postcss-value-parser: 4.2.0 + axios@1.7.7: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.1 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + balanced-match@1.0.2: {} + base32.js@0.1.0: {} + base64-js@1.5.1: {} + base64url@3.0.1: {} + + bigint-conversion@2.4.3: + dependencies: + '@juanelas/base64': 1.1.5 + + bignumber.js@9.1.2: {} + binary-extensions@2.3.0: {} brace-expansion@2.0.1: @@ -3708,6 +3971,22 @@ snapshots: caniuse-lite@1.0.30001666: {} + cbor-extract@2.2.0: + dependencies: + node-gyp-build-optional-packages: 5.1.1 + optionalDependencies: + '@cbor-extract/cbor-extract-darwin-arm64': 2.2.0 + '@cbor-extract/cbor-extract-darwin-x64': 2.2.0 + '@cbor-extract/cbor-extract-linux-arm': 2.2.0 + '@cbor-extract/cbor-extract-linux-arm64': 2.2.0 + '@cbor-extract/cbor-extract-linux-x64': 2.2.0 + '@cbor-extract/cbor-extract-win32-x64': 2.2.0 + optional: true + + cbor-x@1.6.0: + optionalDependencies: + cbor-extract: 2.2.0 + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -3762,6 +4041,10 @@ snapshots: color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + commander@2.20.3: optional: true @@ -3801,12 +4084,17 @@ snapshots: defu@6.1.4: {} + delayed-stream@1.0.0: {} + destr@2.0.3: {} detect-browser@5.3.0: {} detect-libc@1.0.3: {} + detect-libc@2.0.3: + optional: true + detect-node-es@1.1.0: {} didyoumean@1.2.2: {} @@ -3868,6 +4156,8 @@ snapshots: events@3.3.0: {} + eventsource@2.0.2: {} + execa@8.0.1: dependencies: cross-spawn: 7.0.3 @@ -3905,11 +4195,19 @@ snapshots: locate-path: 5.0.0 path-exists: 4.0.0 + follow-redirects@1.15.9: {} + foreground-child@3.3.0: dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + fraction.js@4.3.7: {} framer-motion@11.11.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1): @@ -4145,6 +4443,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + mime@3.0.0: {} mimic-fn@4.0.0: {} @@ -4195,6 +4499,14 @@ snapshots: node-forge@1.3.1: {} + node-gyp-build-optional-packages@5.1.1: + dependencies: + detect-libc: 2.0.3 + optional: true + + node-gyp-build@4.8.2: + optional: true + node-releases@2.0.18: {} normalize-path@3.0.0: {} @@ -4338,6 +4650,8 @@ snapshots: proxy-compare@2.5.1: {} + proxy-from-env@1.1.0: {} + qrcode@1.5.3: dependencies: dijkstrajs: 1.0.3 @@ -4358,6 +4672,10 @@ snapshots: radix3@1.1.2: {} + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 @@ -4490,7 +4808,14 @@ snapshots: set-blocking@2.0.0: {} +<<<<<<< HEAD shallow-equal@3.1.0: {} +======= + sha.js@2.4.11: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 +>>>>>>> ed2751b (Added the contracts env) shebang-command@2.0.0: dependencies: @@ -4500,6 +4825,11 @@ snapshots: signal-exit@4.1.0: {} + sodium-native@4.2.1: + dependencies: + node-gyp-build: 4.8.2 + optional: true + sonic-boom@2.8.0: dependencies: atomic-sleep: 1.0.0 @@ -4521,6 +4851,18 @@ snapshots: std-env@3.7.0: {} + stellar-sdk@12.3.0: + dependencies: + '@stellar/stellar-base': 12.1.1 + axios: 1.7.7 + bignumber.js: 9.1.2 + eventsource: 2.0.2 + randombytes: 2.1.0 + toml: 3.0.0 + urijs: 1.19.11 + transitivePeerDependencies: + - debug + stream-shift@1.0.3: {} strict-uri-encode@2.0.0: {} @@ -4628,6 +4970,8 @@ snapshots: dependencies: is-number: 7.0.0 + toml@3.0.0: {} + tr46@0.0.3: {} ts-interface-checker@0.1.13: {} @@ -4691,6 +5035,8 @@ snapshots: uqr@0.1.2: {} + urijs@1.19.11: {} + use-callback-ref@1.3.2(@types/react@18.3.11)(react@18.3.1): dependencies: react: 18.3.1 diff --git a/dapp/src/App.tsx b/dapp/src/App.tsx index a252d7e..73c136c 100644 --- a/dapp/src/App.tsx +++ b/dapp/src/App.tsx @@ -2,6 +2,7 @@ import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import Home from "./pages/Home"; import Profile from "./pages/Profile"; import Create from "./pages/Create"; +import SoroPass from "./pages/Auth"; import { Toaster } from "./components/ui/toaster"; import Layout from "./components/Layout"; @@ -15,6 +16,7 @@ function App() { } /> } /> } /> + } /> diff --git a/dapp/src/definitions.ts b/dapp/src/definitions.ts new file mode 100644 index 0000000..86fc5de --- /dev/null +++ b/dapp/src/definitions.ts @@ -0,0 +1,8 @@ +import { AuthenticationResponseJSON, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON } from '@simplewebauthn/types'; + +export interface WebAuthnPlugin { + isWebAuthnAvailable(): Promise<{ value: boolean }>; + isWebAuthnAutoFillAvailable(): Promise<{ value: boolean }>; + startRegistration(publicKeyCredentialCreationOptionsJSON: PublicKeyCredentialCreationOptionsJSON): Promise; + startAuthentication(requestOptionsJSON: PublicKeyCredentialRequestOptionsJSON, useBrowserAutofill?: boolean): Promise; +} diff --git a/dapp/src/index.ts b/dapp/src/index.ts new file mode 100644 index 0000000..9b84851 --- /dev/null +++ b/dapp/src/index.ts @@ -0,0 +1,10 @@ +import { registerPlugin } from '@capacitor/core'; + +import type { WebAuthnPlugin } from './definitions'; + +const WebAuthn = registerPlugin('WebAuthn', { + web: () => import('./web').then(m => new m.WebAuthnWeb()), +}); + +export * from './definitions'; +export { WebAuthn }; diff --git a/dapp/src/lib/deploy.ts b/dapp/src/lib/deploy.ts new file mode 100644 index 0000000..1e9b4d7 --- /dev/null +++ b/dapp/src/lib/deploy.ts @@ -0,0 +1,69 @@ +import { Keypair, StrKey, xdr, hash, Address, Account, TransactionBuilder, Operation, SorobanRpc } from "@stellar/stellar-sdk" + +async function handleDeploy(bundlerKey: Keypair, contractSalt: Buffer, publicKey?: Buffer) { + console.log(import.meta.env.VITE_PUBLIC_rpcUrl) + const rpc = new SorobanRpc.Server(import.meta.env.VITE_PUBLIC_rpcUrl); + const deployee = StrKey.encodeContract(hash(xdr.HashIdPreimage.envelopeTypeContractId( + new xdr.HashIdPreimageContractId({ + networkId: hash(Buffer.from(import.meta.env.VITE_PUBLIC_networkPassphrase, 'utf-8')), + contractIdPreimage: xdr.ContractIdPreimage.contractIdPreimageFromAddress( + new xdr.ContractIdPreimageFromAddress({ + address: Address.fromString(import.meta.env.VITE_PUBLIC_factoryContractId).toScAddress(), + salt: contractSalt, + }) + ) + }) + ).toXDR())); + console.log(deployee) + // This is a signup deploy vs a signin deploy. Look up if this contract has been already been deployed, otherwise fail + if (!publicKey) { + await rpc.getContractData(deployee, xdr.ScVal.scvLedgerKeyContractInstance()) + return deployee + } + + const bundlerKeyAccount = await rpc.getAccount(bundlerKey.publicKey()).then((res) => new Account(res.accountId(), res.sequenceNumber())) + const simTxn = new TransactionBuilder(bundlerKeyAccount, { + fee: '100', + networkPassphrase: import.meta.env.VITE_PUBLIC_networkPassphrase + }) + .addOperation( + Operation.invokeContractFunction({ + contract: import.meta.env.VITE_PUBLIC_factoryContractId, + function: 'deploy', + args: [ + xdr.ScVal.scvBytes(contractSalt), + xdr.ScVal.scvBytes(publicKey), + ] + }) + ) + .setTimeout(0) + .build(); + + const sim = await rpc.simulateTransaction(simTxn) + + if ( + SorobanRpc.Api.isSimulationError(sim) + || SorobanRpc.Api.isSimulationRestore(sim) + ) throw sim + + const transaction = SorobanRpc.assembleTransaction(simTxn, sim).setTimeout(0).build() + + transaction.sign(bundlerKey); + + // TODO failure here is resulting in sp:deployee undefined + // TODO handle archived entries + + const txResp = await (await fetch(`${import.meta.env.VITE_PUBLIC_horizonUrl}/transactions`, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ 'tx': transaction.toXDR() }), + })).json(); + + if (txResp.successful) { + return deployee + } else { + throw txResp + } +} + +export { handleDeploy } diff --git a/dapp/src/lib/get_votes.ts b/dapp/src/lib/get_votes.ts new file mode 100644 index 0000000..edf208a --- /dev/null +++ b/dapp/src/lib/get_votes.ts @@ -0,0 +1,50 @@ +import { SorobanRpc } from "@stellar/stellar-sdk"; +import { Keypair, xdr, Address, Operation, TransactionBuilder, Account, scValToNative } from "@stellar/stellar-sdk"; + +export async function getVotes(bundlerKey: Keypair, accountContractId: string) { + const key = bundlerKey; + + const op = Operation.invokeContractFunction({ + contract: import.meta.env.VITE_PUBLIC_chickenVsEggContractId, + function: 'votes', + args: [ + xdr.ScVal.scvAddress(Address.fromString(accountContractId).toScAddress()) + ] + }) + + const transaction = new TransactionBuilder( + new Account(key.publicKey(), '0'), + { fee: '0', networkPassphrase: import.meta.env.VITE_PUBLIC_networkPassphrase }, + ) + .addOperation(op) + .setTimeout(0) + .build(); + + const rpc = new SorobanRpc.Server(import.meta.env.VITE_PUBLIC_rpcUrl); + + const simResp = await rpc.simulateTransaction(transaction) + + if (!SorobanRpc.Api.isSimulationSuccess(simResp)) { + throw simResp; + } else { + const [all_votes, source_votes]: [{chicken: number, egg: number}, {chicken: number, egg: number}] = scValToNative(simResp.result?.retval!) + const total_all_votes = all_votes.chicken + all_votes.egg + + return { + all_votes: { + ...all_votes, + chicken_percent: all_votes.chicken / total_all_votes * 100, + egg_percent: all_votes.egg / total_all_votes * 100, + chicken_percent_no_source: (all_votes.chicken - source_votes.chicken) / total_all_votes * 100, + egg_percent_no_source: (all_votes.egg - source_votes.egg) / total_all_votes * 100 + }, + source_votes: { + ...source_votes, + chicken_percent: source_votes.chicken / total_all_votes * 100, + egg_percent: source_votes.egg / total_all_votes * 100 + }, + total_source_votes: source_votes.chicken + source_votes.egg, + total_all_votes + }; + } +} \ No newline at end of file diff --git a/dapp/src/lib/vote_build.ts b/dapp/src/lib/vote_build.ts new file mode 100644 index 0000000..2994eda --- /dev/null +++ b/dapp/src/lib/vote_build.ts @@ -0,0 +1,49 @@ + +import { Account, Address, Keypair, Operation, SorobanRpc, TransactionBuilder, hash, xdr } from "@stellar/stellar-sdk"; + +export async function handleVoteBuild(bundlerKey: Keypair, accountContractId: string, vote: boolean) { + const rpc = new SorobanRpc.Server(import.meta.env.VITE_PUBLIC_rpcUrl); + const lastLedger = await rpc.getLatestLedger().then(({ sequence }) => sequence) + const bundlerKeyAccount = await rpc.getAccount(bundlerKey.publicKey()).then((res) => new Account(res.accountId(), res.sequenceNumber())) + + const simTxn = new TransactionBuilder(bundlerKeyAccount, { + fee: '0', + networkPassphrase: import.meta.env.VITE_PUBLIC_networkPassphrase + }) + .addOperation(Operation.invokeContractFunction({ + contract: import.meta.env.VITE_PUBLIC_chickenVsEggContractId, + function: 'vote', + args: [ + Address.fromString(accountContractId).toScVal(), + xdr.ScVal.scvBool(vote) + ] + })) + .setTimeout(0) + .build() + + const sim = await rpc.simulateTransaction(simTxn) + + if ( + SorobanRpc.Api.isSimulationError(sim) + || SorobanRpc.Api.isSimulationRestore(sim) + ) throw sim + + const authTxn = SorobanRpc.assembleTransaction(simTxn, sim).build() + const auth = sim.result?.auth[0]! + const authHash = hash( + xdr.HashIdPreimage.envelopeTypeSorobanAuthorization( + new xdr.HashIdPreimageSorobanAuthorization({ + networkId: hash(Buffer.from(import.meta.env.VITE_PUBLIC_networkPassphrase, 'utf-8')), + nonce: auth.credentials().address().nonce(), + signatureExpirationLedger: lastLedger + 100, + invocation: auth.rootInvocation() + }) + ).toXDR() + ) + + return { + authTxn, + authHash, + lastLedger + } +} \ No newline at end of file diff --git a/dapp/src/lib/vote_send.ts b/dapp/src/lib/vote_send.ts new file mode 100644 index 0000000..700716c --- /dev/null +++ b/dapp/src/lib/vote_send.ts @@ -0,0 +1,54 @@ +import { Memo, Operation, SorobanRpc, Transaction, xdr, type Keypair, type MemoType } from "@stellar/stellar-sdk"; +import base64url from "base64url"; +import { convertEcdsaSignatureAsnToCompact } from "./webauthn"; + +export async function handleVoteSend(bundlerKey: Keypair, authTxn: Transaction, Operation[]>, lastLedger: number, signRes: any) { + const rpc = new SorobanRpc.Server(import.meta.env.VITE_PUBLIC_rpcUrl); + + const signatureRaw = base64url.toBuffer(signRes.response.signature); + const signature = convertEcdsaSignatureAsnToCompact(signatureRaw); + + const op = authTxn.operations[0] as Operation.InvokeHostFunction + const creds = op.auth?.[0].credentials().address()! + + creds.signatureExpirationLedger(lastLedger + 100) + creds.signature(xdr.ScVal.scvMap([ + new xdr.ScMapEntry({ + key: xdr.ScVal.scvSymbol('authenticator_data'), + val: xdr.ScVal.scvBytes(base64url.toBuffer(signRes.response.authenticatorData)), + }), + new xdr.ScMapEntry({ + key: xdr.ScVal.scvSymbol('client_data_json'), + val: xdr.ScVal.scvBytes(base64url.toBuffer(signRes.response.clientDataJSON)), + }), + new xdr.ScMapEntry({ + key: xdr.ScVal.scvSymbol('signature'), + val: xdr.ScVal.scvBytes(signature), + }), + ])) + + const sim = await rpc.simulateTransaction(authTxn) + + if ( + SorobanRpc.Api.isSimulationError(sim) + || SorobanRpc.Api.isSimulationRestore(sim) + ) throw sim + + const transaction = SorobanRpc.assembleTransaction(authTxn, sim) + .setTimeout(30) + .build() + + transaction.sign(bundlerKey) + + const txResp = await (await fetch(`${import.meta.env.VITE_PUBLIC_horizonUrl}/transactions`, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ 'tx': transaction.toXDR() }), + })).json(); + + if (txResp.successful) { + console.log(txResp); + } else { + throw txResp; + } +} \ No newline at end of file diff --git a/dapp/src/lib/webauthn.ts b/dapp/src/lib/webauthn.ts new file mode 100644 index 0000000..bcad4e1 --- /dev/null +++ b/dapp/src/lib/webauthn.ts @@ -0,0 +1,259 @@ +import * as CBOR from 'cbor-x/decode' +import base64url from 'base64url'; +import { bufToBigint, bigintToBuf } from 'bigint-conversion' +import { hash } from '@stellar/stellar-sdk'; + +// WebAuthn.startRegistration +// (web) +// { +// "id": "H4IsVi6YBjl1OYD7D8grqndtCLc", +// "rawId": "H4IsVi6YBjl1OYD7D8grqndtCLc", +// "response": { +// "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViYK6IVONck2rpXYfkLEGUqpBJhNdZXyHOXyWvGrTtRJpVdAAAAAPv8MAcVTk7MjAtuAgVX170AFB-CLFYumAY5dTmA-w_IK6p3bQi3pQECAyYgASFYIGW9SIVw0IkjsGcpWa4Wx2VZdYvEkdjPS-bqxX85M29HIlggc0GQb1oRSzTfx46AM1DNKRJ_p6wKjZRR9g5bz8LsiM8", +// "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiWTNKbFlYUmxZMmhoYkd4bGJtZGwiLCJvcmlnaW4iOiJodHRwczovL3Bhc3NrZXkuc29yb2JhbmJ5ZXhhbXBsZS5vcmciLCJjcm9zc09yaWdpbiI6ZmFsc2V9", +// "transports": [ +// "hybrid", +// "internal" +// ], +// "publicKeyAlgorithm": -7, +// "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZb1IhXDQiSOwZylZrhbHZVl1i8SR2M9L5urFfzkzb0dzQZBvWhFLNN_HjoAzUM0pEn-nrAqNlFH2DlvPwuyIzw", +// "authenticatorData": "K6IVONck2rpXYfkLEGUqpBJhNdZXyHOXyWvGrTtRJpVdAAAAAPv8MAcVTk7MjAtuAgVX170AFB-CLFYumAY5dTmA-w_IK6p3bQi3pQECAyYgASFYIGW9SIVw0IkjsGcpWa4Wx2VZdYvEkdjPS-bqxX85M29HIlggc0GQb1oRSzTfx46AM1DNKRJ_p6wKjZRR9g5bz8LsiM8" +// }, +// "type": "public-key", +// "clientExtensionResults": {}, +// "authenticatorAttachment": "platform" +// } + +// (ios) +// { +// "id": "FNvVPJP3hmWrGfbGrfHjJYrK72s", +// "type": "public-key", +// "authenticatorAttachment": "platform", +// "rawId": "FNvVPJP3hmWrGfbGrfHjJYrK72s", +// "response": { +// "transports": [ +// "internal" +// ], +// "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiWTNKbFlYUmxZMmhoYkd4bGJtZGwiLCJvcmlnaW4iOiJodHRwczovL3Bhc3NrZXkuc29yb2JhbmJ5ZXhhbXBsZS5vcmcifQ", +// "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViYK6IVONck2rpXYfkLEGUqpBJhNdZXyHOXyWvGrTtRJpVdAAAAAPv8MAcVTk7MjAtuAgVX170AFBTb1TyT94Zlqxn2xq3x4yWKyu9rpQECAyYgASFYIMQDtLI1TS_oC8p8G1WJyVQhgk6HEEV6oh_fzzffMNrwIlggEcUe0F_AsXcYPK2VnbNqAGOtx6r00KfryoHTL7ZeF-E" +// } +// } + +// WebAuthn.startAuthentication +// (web) +// { +// "id": "H4IsVi6YBjl1OYD7D8grqndtCLc", +// "rawId": "H4IsVi6YBjl1OYD7D8grqndtCLc", +// "response": { +// "authenticatorData": "K6IVONck2rpXYfkLEGUqpBJhNdZXyHOXyWvGrTtRJpUdAAAAAA", +// "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiWTNKbFlYUmxZMmhoYkd4bGJtZGwiLCJvcmlnaW4iOiJodHRwczovL3Bhc3NrZXkuc29yb2JhbmJ5ZXhhbXBsZS5vcmciLCJjcm9zc09yaWdpbiI6ZmFsc2V9", +// "signature": "MEQCIHf6wXsVbm3Nv2AdmdUxHh-mfG60Y3Omu7-gfFBaV4G_AiB2BQPWiyuxEOJssAM0fP4MUwKA_q_1ybReU_mqWY2c9A", +// "userHandle": "U29yb2JhbiBUZXN0" +// }, +// "type": "public-key", +// "clientExtensionResults": {}, +// "authenticatorAttachment": "platform" +// } + +// (ios) +// { +// "authenticatorAttachment": "platform", +// "rawId": "H4IsVi6YBjl1OYD7D8grqndtCLc", +// "type": "public-key", +// "id": "H4IsVi6YBjl1OYD7D8grqndtCLc", +// "response": { +// "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiWTNKbFlYUmxZMmhoYkd4bGJtZGwiLCJvcmlnaW4iOiJodHRwczovL3Bhc3NrZXkuc29yb2JhbmJ5ZXhhbXBsZS5vcmcifQ", +// "authenticatorData": "K6IVONck2rpXYfkLEGUqpBJhNdZXyHOXyWvGrTtRJpUdAAAAAA", +// "userHandle": "VTI5eWIySmhiaUJVWlhOMA", +// "signature": "MEUCIFlHfLFaHULwdwDXVS3rJcxKNIsxbN3D58Lxys9cDK2uAiEA6Un1AQ0HVPyAya_ZXYiVB9Bvv1JesAfgQLATtCPFEI0" +// } +// } + +// await navigator.credentials.create({ +// publicKey: { +// challenge: new Uint8Array([114,183,154,181,231,33,106,89,94,158,7]), +// rp: { +// name: "Soroban Test", +// }, +// user: { +// id: new Uint8Array([74,138,232,109,169,211,122,203]), +// name: "Soroban Test", +// displayName: "Soroban Test", +// }, +// authenticatorSelection: { +// requireResidentKey: false, +// residentKey: "preferred", +// userVerification: "preferred", +// }, +// pubKeyCredParams: [{ alg: -7, type: "public-key" }], +// } +// }) + +// await navigator.credentials.get({ +// publicKey: { +// challenge: new Uint8Array([114, 183, 154, 181, 231, 33, 106, 89, 94, 158, 7]), +// allowCredentials: [ +// { +// id: new Uint8Array([0, 90, 10, 58, 192, 177, 171, 4, 207, 100, 116, 41, 95, 52, 18, 182]), +// type: "public-key", +// }, +// ], +// userVerification: "discouraged", +// } +// }) + +export async function getPublicKeys(registration: any) { + const contractSalt = hash(base64url.toBuffer(registration.id)) + + console.log(JSON.stringify(registration, null, 2)); + + if (registration.response.attestationObject) { + const { publicKeyObject } = getPublicKeyObject(registration.response.attestationObject); + const publicKey = Buffer.from([ + 4, // (0x04 prefix) https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm + ...publicKeyObject.get('-2')!, + ...publicKeyObject.get('-3')! + ]) + + return { + contractSalt, + publicKey + } + } + + else { + return { + contractSalt + } + } +} + +function getPublicKeyObject(attestationObject: string) { + const { authData } = CBOR.decode(base64url.toBuffer(attestationObject)); + const authDataUint8Array = new Uint8Array(authData); + const authDataView = new DataView(authDataUint8Array.buffer, 0, authDataUint8Array.length); + + let offset = 0; + + // RP ID Hash (32 bytes) + const rpIdHash = authData.slice(offset, offset + 32); + offset += 32; + + // Flags (1 byte) + const flags = authDataView.getUint8(offset); + offset += 1; + + // Sign Count (4 bytes, big endian) + const signCount = authDataView.getUint32(offset, false); + offset += 4; + + // Attested Credential Data, if present + if (flags & 0x40) { // Checking the AT flag + // AAGUID (16 bytes) + const aaguid = authData.slice(offset, offset + 16); + offset += 16; + + // Credential ID Length (2 bytes, big endian) + const credIdLength = authDataView.getUint16(offset, false); + offset += 2; + + // Credential ID (variable length) + const credentialId = authData.slice(offset, offset + credIdLength); + offset += credIdLength; + + // Credential Public Key - (77 bytes...I hope) + const credentialPublicKey = authData.slice(offset, offset + 77); + offset += 77; + + // Any leftover bytes. I found some when using a YubiKey + const theRest = authData.slice(offset); + + // Decode the credential public key to COSE + const publicKeyObject = new Map(Object.entries(CBOR.decode(credentialPublicKey))); + + return { + rpIdHash, + flags, + signCount, + aaguid, + credIdLength, + credentialId, + credentialPublicKey, + theRest, + publicKeyObject + }; + } + + throw new Error("Attested credential data not present in the flags."); +} + +export function convertEcdsaSignatureAsnToCompact(sig: Buffer) { + // Define the order of the curve secp256k1 + // https://github.com/RustCrypto/elliptic-curves/blob/master/p256/src/lib.rs#L72 + const q = Buffer.from('ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551', 'hex') + + // ASN Sequence + let offset = 0; + if (sig[offset] != 0x30) { + throw "signature is not a sequence"; + } + offset += 1; + + // ASN Sequence Byte Length + offset += 1; + + // ASN Integer (R) + if (sig[offset] != 0x02) { + throw "first element in sequence is not an integer"; + } + offset += 1; + + // ASN Integer (R) Byte Length + const rLen = sig[offset]; + offset += 1; + + // ASN Integer (R) Byte Value + if (rLen >= 33) { + if (rLen != 33 || sig[offset] != 0x00) { + throw "can only handle larger than 32 byte R's that are len 33 and lead with zero"; + } + offset += 1; + } + const r = sig.slice(offset, offset + 32); + offset += 32; + + // ASN Integer (S) + if (sig[offset] != 0x02) { + throw "second element in sequence is not an integer"; + } + offset += 1; + + // ASN Integer (S) Byte Length + const sLen = sig[offset]; + offset += 1; + + // ASN Integer (S) Byte Value + if (sLen >= 33) { + if (sLen != 33 || sig[offset] != 0x00) { + throw "can only handle larger than 32 byte R's that are len 33 and lead with zero"; + } + offset += 1; + } + + const s = sig.slice(offset, offset + 32); + + offset += 32; + + let signature64 + + // Force low S range + // https://github.com/stellar/stellar-protocol/discussions/1435#discussioncomment-8809175 + // https://discord.com/channels/897514728459468821/1233048618571927693 + if (bufToBigint(s) > ((bufToBigint(q) - BigInt(1)) / BigInt(2))) { + signature64 = Buffer.from([...r, ...Buffer.from(bigintToBuf(bufToBigint(q) - bufToBigint(s)))]); + } else { + signature64 = Buffer.from([...r, ...s]); + } + + return signature64; +} \ No newline at end of file diff --git a/dapp/src/pages/Auth.tsx b/dapp/src/pages/Auth.tsx new file mode 100644 index 0000000..a0de1fa --- /dev/null +++ b/dapp/src/pages/Auth.tsx @@ -0,0 +1,348 @@ +import React, { useState, useEffect, useCallback } from 'react'; +import { WebAuthn } from "@darkedges/capacitor-native-webauthn"; +import { Buffer } from 'buffer'; +import base64url from "base64url"; +import { Capacitor } from "@capacitor/core"; +import { Horizon, Keypair } from "@stellar/stellar-sdk"; +import { Share } from "@capacitor/share"; +import { motion, AnimatePresence } from "framer-motion"; + +// Import environment variables +const PUBLIC_horizonUrl = import.meta.env.VITE_PUBLIC_horizonUrl; + +// Helper functions (these would need to be implemented or imported) +import { getPublicKeys } from "../lib/webauthn"; +import { handleDeploy } from "../lib/deploy"; +import { handleVoteBuild } from "../lib/vote_build"; +import { handleVoteSend } from "../lib/vote_send"; +import { getVotes } from "../lib/get_votes"; + +if (typeof window !== 'undefined') { + window.Buffer = Buffer; +} + +const SoroPass: React.FC = () => { + const [deployee, setDeployee] = useState(null); + const [bundlerKey, setBundlerKey] = useState(null); + const [votes, setVotes] = useState({ + all_votes: { + chicken: 0, + egg: 0, + chicken_percent: 0, + egg_percent: 0, + chicken_percent_no_source: 0, + egg_percent_no_source: 0, + }, + source_votes: { + chicken: 0, + egg: 0, + chicken_percent: 0, + egg_percent: 0, + }, + total_source_votes: 0, + total_all_votes: 0, + }); + const [loadingRegister, setLoadingRegister] = useState(false); + const [loadingSign, setLoadingSign] = useState(false); + const [step, setStep] = useState(0); + const [dots, setDots] = useState(""); + const [choice, setChoice] = useState(null); + + useEffect(() => { + setTimeout(() => setStep(1), 500); + + const dotInterval = setInterval(() => { + setDots(prev => prev.length === 3 ? "" : prev + "."); + }, 500); + + const voteInterval = setInterval(() => onVotes(), 25000); + + if (localStorage.hasOwnProperty("sp:bundler")) { + setBundlerKey(Keypair.fromSecret(localStorage.getItem("sp:bundler")!)); + } else { + const newBundlerKey = Keypair.random(); + setBundlerKey(newBundlerKey); + localStorage.setItem("sp:bundler", newBundlerKey.secret()); + + const horizon = new Horizon.Server(import.meta.env.PUBLIC_horizonUrl!); + horizon.friendbot(newBundlerKey.publicKey()).call(); + } + + console.log("is local storage", localStorage); + + if (localStorage.hasOwnProperty("sp:deployee")) { + setDeployee(localStorage.getItem("sp:deployee")); + onVotes(); + } + + return () => { + clearInterval(dotInterval); + clearInterval(voteInterval); + }; + }, []); + + const onRegister = useCallback(async (type?: "signin") => { + if (!type && deployee) { + setStep(prev => prev + 1); + return; + } + + try { + setLoadingRegister(true); + + const isWebAuthnAvailable = await WebAuthn.isWebAuthnAvailable(); + if (!isWebAuthnAvailable.value) { + throw new Error("WebAuthn is not available on this device"); + } + + let registerRes; + if (type === "signin") { + registerRes = await WebAuthn.startAuthentication({ + challenge: base64url("createchallenge"), + rpId: Capacitor.isNativePlatform() ? "passkey.sorobanbyexample.org" : undefined, + userVerification: "discouraged", + }); + } else { + registerRes = await WebAuthn.startRegistration({ + challenge: base64url(Buffer.from("createchallenge")), + rp: { + id: Capacitor.isNativePlatform() ? "passkey.sorobanbyexample.org" : undefined, + name: "SoroPass", + }, + user: { + id: base64url("Soroban Test"), + name: "Soroban Test", + displayName: "Soroban Test", + }, + authenticatorSelection: { + requireResidentKey: false, + residentKey: Capacitor.getPlatform() === "android" ? "preferred" : "discouraged", + userVerification: "discouraged", + }, + pubKeyCredParams: [{ alg: -7, type: "public-key" }], + attestation: "none", + }); + } + + localStorage.setItem("sp:id", registerRes.id); + + const { contractSalt, publicKey } = await getPublicKeys(registerRes); + const newDeployee = await handleDeploy(bundlerKey!, contractSalt, publicKey!); + setDeployee(newDeployee); + console.log("Logged in as", newDeployee); + setStep(prev => prev + 1); + } catch (error) { + console.error(error); + alert(JSON.stringify(error)); + } finally { + setLoadingRegister(false); + } + }, [bundlerKey, deployee]); + + + + const onSign = useCallback(async () => { + try { + setLoadingSign(true); + + let { authTxn, authHash, lastLedger } = await handleVoteBuild( + bundlerKey!, + deployee!, + choice === "chicken", + ); + + const signRes = await WebAuthn.startAuthentication({ + challenge: base64url(authHash), + rpId: Capacitor.isNativePlatform() + ? "passkey.sorobanbyexample.org" + : undefined, + allowCredentials: localStorage.hasOwnProperty("sp:id") + ? [ + { + id: localStorage.getItem("sp:id")!, + type: "public-key", + }, + ] + : undefined, + userVerification: "discouraged", + }); + + await handleVoteSend(bundlerKey!, authTxn, lastLedger, signRes); + await onVotes(); + setStep(prev => prev + 1); + } catch (error) { + console.error(error); + alert(JSON.stringify(error)); + } finally { + setLoadingSign(false); + } + }, [bundlerKey, deployee, choice]); + + const onVotes = useCallback(async () => { + if (bundlerKey && deployee) { + const newVotes = await getVotes(bundlerKey, deployee); + setVotes(newVotes); + console.log("NewVote", newVotes); + } + }, [bundlerKey, deployee]); + + const truncateAccount = (account: string) => { + return `${account.slice(0, 5)}...${account.slice(-5)}`; + }; + + const swipeHandler = (event: any) => { + if (event.detail.direction === "right") goLeft(); + else if (event.detail.direction === "left") goRight(); + }; + + const tapHandler = (event: any) => { + if ( + !["div", "h1", "p"].includes( + event.detail.target.tagName.toLowerCase() + ) + ) + return; + else if ( + document.querySelector("#soropass")?.clientWidth! / 2 > + event.detail.x + ) + goLeft(); + else goRight(); + }; + + const goLeft = () => { + if (!(step <= 1)) setStep(prev => prev - 1); + }; + + const goRight = () => { + if ( + !( + step >= 14 || + (step === 5 && !deployee) || + (step === 10 && !choice && !votes?.total_source_votes) || + (step === 11 && !votes?.total_source_votes) + ) + ) + setStep(prev => prev + 1); + }; + + const shareContent = async () => { + const { value } = await Share.canShare(); + + if (value) { + await Share.share({ + title: "Share SoroPass", + text: "Check out this blockchain experience powered by your face or fingers!", + url: "https://passkey.sorobanbyexample.org/", + dialogTitle: `${choice === "chicken" ? 'Chicken 🐔' : 'Egg 🥚'} people unite!`, + }); + } else { + window.open( + `https://twitter.com/intent/tweet?text=${encodeURIComponent("Check out this blockchain experience powered by your face or fingers!")}&url=${encodeURIComponent("https://passkey.sorobanbyexample.org/")}`, + ); + } + }; + + const resetAll = () => { + localStorage.removeItem("sp:id"); + localStorage.removeItem("sp:bundler"); + localStorage.removeItem("sp:deployee"); + window.location.reload(); + }; + + return ( +
{ + const touch = e.touches[0]; + const startX = touch.clientX; + const startY = touch.clientY; + + const handleTouchEnd = (e: TouchEvent) => { + const touch = e.changedTouches[0]; + const endX = touch.clientX; + const endY = touch.clientY; + + const deltaX = endX - startX; + const deltaY = endY - startY; + + if (Math.abs(deltaX) > Math.abs(deltaY)) { + if (deltaX > 100) { + swipeHandler({ detail: { direction: "right" } }); + } else if (deltaX < -100) { + swipeHandler({ detail: { direction: "left" } }); + } + } + + document.removeEventListener('touchend', handleTouchEnd); + }; + + document.addEventListener('touchend', handleTouchEnd); + }} + onClick={(e) => tapHandler({ detail: { target: e.target, x: e.clientX } })} + > + + {step === 1 && ( + +

Welcome!

+

Split is a fun and secure way to vote using blockchain technology.

+ + + + +
+ )} + + + {step === 5 && ( + +

Register or Sign In

+

Use your device's biometrics to create or access your account.

+ + +
+ )} + + +
+
+ ); +}; + +export default SoroPass; \ No newline at end of file diff --git a/dapp/src/web.ts b/dapp/src/web.ts new file mode 100644 index 0000000..52b7496 --- /dev/null +++ b/dapp/src/web.ts @@ -0,0 +1,48 @@ +import { WebPlugin } from '@capacitor/core'; +import { browserSupportsWebAuthn, browserSupportsWebAuthnAutofill, startAuthentication, startRegistration } from '@simplewebauthn/browser'; +import { AuthenticationResponseJSON, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON } from '@simplewebauthn/types'; + +import type { WebAuthnPlugin } from './definitions'; + +export class WebAuthnWeb extends WebPlugin implements WebAuthnPlugin { + + async startRegistration(publicKeyCredentialCreationOptionsJSON: PublicKeyCredentialCreationOptionsJSON): Promise { + let res; + try { + res = await startRegistration(publicKeyCredentialCreationOptionsJSON); + } catch (error) { + return Promise.reject(error) + } + return Promise.resolve(res) + } + + async startAuthentication(requestOptionsJSON: PublicKeyCredentialRequestOptionsJSON, useBrowserAutofill?: boolean): Promise { + let res; + try { + res = await startAuthentication(requestOptionsJSON, useBrowserAutofill); + } catch (error) { + return Promise.reject(error) + } + return Promise.resolve(res) + } + + async isWebAuthnAvailable(): Promise<{ value: boolean }> { + return this.isAvailable('webauthn'); + } + + async isWebAuthnAutoFillAvailable(): Promise<{ value: boolean }> { + return this.isAvailable('webauthnautofill'); + } + + private async isAvailable(type: 'webauthn' | 'webauthnautofill'): Promise<{ value: boolean }> { + let val = false; + if (type === 'webauthn') { + val = await browserSupportsWebAuthn(); + } + if (type === 'webauthnautofill') { + val = await browserSupportsWebAuthnAutofill(); + } + return Promise.resolve({ value: val }); + } + +} From f855752cbaea4c6a400274d34b99d127d2991922 Mon Sep 17 00:00:00 2001 From: cindytrang Date: Sun, 13 Oct 2024 02:15:52 +0100 Subject: [PATCH 2/2] Added the changes to the Auth.tsx. --- dapp/src/pages/Auth.tsx | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/dapp/src/pages/Auth.tsx b/dapp/src/pages/Auth.tsx index a0de1fa..1c44386 100644 --- a/dapp/src/pages/Auth.tsx +++ b/dapp/src/pages/Auth.tsx @@ -55,7 +55,7 @@ const SoroPass: React.FC = () => { setDots(prev => prev.length === 3 ? "" : prev + "."); }, 500); - const voteInterval = setInterval(() => onVotes(), 25000); + const voteInterval = setInterval(() => onVotes(), 1500); if (localStorage.hasOwnProperty("sp:bundler")) { setBundlerKey(Keypair.fromSecret(localStorage.getItem("sp:bundler")!)); @@ -167,9 +167,10 @@ const SoroPass: React.FC = () => { userVerification: "discouraged", }); - await handleVoteSend(bundlerKey!, authTxn, lastLedger, signRes); + const respone = await handleVoteSend(bundlerKey!, authTxn, lastLedger, signRes); await onVotes(); setStep(prev => prev + 1); + console.log("Vote sent", respone, "Signature", signRes); } catch (error) { console.error(error); alert(JSON.stringify(error)); @@ -297,16 +298,13 @@ const SoroPass: React.FC = () => { >

Welcome!

Split is a fun and secure way to vote using blockchain technology.

- - + )} @@ -339,9 +337,15 @@ const SoroPass: React.FC = () => { )} - - + + + + ); };