From 85929df8b60fd4373b501111eeae28e1abd9adb7 Mon Sep 17 00:00:00 2001 From: girogio Date: Tue, 20 Feb 2024 09:47:25 +0100 Subject: [PATCH 1/3] Project restructure --- .pre-commit-config.yaml | 2 +- src-tauri/.gitignore | 4 + src-tauri/Cargo.lock | 7561 +++++++++++++++++ src-tauri/Cargo.toml | 94 + src-tauri/build.rs | 3 + src-tauri/capabilities/capabilities.toml | 20 + src-tauri/icons/128x128.png | Bin 0 -> 2837 bytes src-tauri/icons/128x128@2x.png | Bin 0 -> 2837 bytes src-tauri/icons/32x32.png | Bin 0 -> 879 bytes src-tauri/icons/icon.icns | Bin 0 -> 3890 bytes src-tauri/icons/icon.ico | Bin 0 -> 4286 bytes src-tauri/icons/icon.png | Bin 0 -> 2837 bytes src-tauri/src/api.rs | 6 + src-tauri/src/api/aleo_client.rs | 121 + src-tauri/src/api/client.rs | 100 + src-tauri/src/api/encrypted_data.rs | 704 ++ src-tauri/src/api/fee.rs | 176 + src-tauri/src/api/tokens.rs | 52 + src-tauri/src/api/user.rs | 259 + src-tauri/src/helpers.rs | 3 + src-tauri/src/helpers/upgrade.rs | 58 + src-tauri/src/helpers/utils.rs | 67 + src-tauri/src/helpers/validation.rs | 145 + src-tauri/src/lib.rs | 102 + src-tauri/src/main.rs | 13 + src-tauri/src/models.rs | 9 + src-tauri/src/models/account.rs | 24 + src-tauri/src/models/auth.rs | 134 + src-tauri/src/models/event.rs | 346 + src-tauri/src/models/event_payloads.rs | 10 + src-tauri/src/models/pointers.rs | 5 + src-tauri/src/models/pointers/deployment.rs | 377 + src-tauri/src/models/pointers/message.rs | 115 + src-tauri/src/models/pointers/record.rs | 255 + src-tauri/src/models/pointers/transaction.rs | 660 ++ src-tauri/src/models/pointers/transition.rs | 357 + src-tauri/src/models/storage/encryption.rs | 48 + src-tauri/src/models/storage/languages.rs | 84 + src-tauri/src/models/storage/mod.rs | 3 + src-tauri/src/models/storage/persistent.rs | 132 + src-tauri/src/models/transfer.rs | 83 + src-tauri/src/models/wallet.rs | 269 + src-tauri/src/models/wallet_connect.rs | 6 + .../src/models/wallet_connect/balance.rs | 82 + .../src/models/wallet_connect/create_event.rs | 80 + .../src/models/wallet_connect/decrypt.rs | 24 + src-tauri/src/models/wallet_connect/deploy.rs | 1 + .../src/models/wallet_connect/get_event.rs | 123 + .../src/models/wallet_connect/records.rs | 203 + src-tauri/src/models/wallet_connect/sign.rs | 55 + src-tauri/src/services.rs | 6 + src-tauri/src/services/README.md | 43 + src-tauri/src/services/account.rs | 4 + src-tauri/src/services/account/generation.rs | 159 + .../src/services/account/key_management.rs | 2 + .../account/key_management/android.rs | 719 ++ .../account/key_management/desktop.rs | 229 + .../services/account/key_management/iOS.rs | 244 + .../account/key_management/key_controller.rs | 207 + .../src/services/account/phrase_recovery.rs | 96 + .../src/services/account/shard_recovery.rs | 1 + src-tauri/src/services/account/utils.rs | 76 + src-tauri/src/services/authentication.rs | 7 + .../src/services/authentication/android.rs | 39 + src-tauri/src/services/authentication/ios.rs | 37 + .../src/services/authentication/session.rs | 327 + src-tauri/src/services/local_storage.rs | 6 + .../services/local_storage/encrypted_data.rs | 794 ++ .../local_storage/persistent_storage.rs | 489 ++ .../src/services/local_storage/session.rs | 2 + .../local_storage/session/password.rs | 75 + .../services/local_storage/session/view.rs | 59 + .../src/services/local_storage/storage_api.rs | 6 + .../local_storage/storage_api/deployment.rs | 147 + .../local_storage/storage_api/event.rs | 539 ++ .../local_storage/storage_api/records.rs | 641 ++ .../local_storage/storage_api/transaction.rs | 471 + .../local_storage/storage_api/transition.rs | 123 + .../src/services/local_storage/tokens.rs | 328 + src-tauri/src/services/local_storage/utils.rs | 345 + src-tauri/src/services/record_handling.rs | 5 + .../record_handling/decrypt_transition.rs | 668 ++ .../src/services/record_handling/docs.md | 4 + .../src/services/record_handling/records.rs | 800 ++ .../src/services/record_handling/sync.rs | 805 ++ .../src/services/record_handling/transfer.rs | 1413 +++ .../src/services/record_handling/utils.rs | 2092 +++++ src-tauri/src/services/records.rs | 127 + src-tauri/src/services/wallet_connect_api.rs | 1011 +++ src-tauri/tauri.conf.json | 56 + src-tauri/tauri.windows.conf.json | 7 + 91 files changed, 26183 insertions(+), 1 deletion(-) create mode 100644 src-tauri/.gitignore create mode 100644 src-tauri/Cargo.lock create mode 100644 src-tauri/Cargo.toml create mode 100644 src-tauri/build.rs create mode 100644 src-tauri/capabilities/capabilities.toml create mode 100644 src-tauri/icons/128x128.png create mode 100644 src-tauri/icons/128x128@2x.png create mode 100644 src-tauri/icons/32x32.png create mode 100644 src-tauri/icons/icon.icns create mode 100644 src-tauri/icons/icon.ico create mode 100644 src-tauri/icons/icon.png create mode 100644 src-tauri/src/api.rs create mode 100644 src-tauri/src/api/aleo_client.rs create mode 100644 src-tauri/src/api/client.rs create mode 100644 src-tauri/src/api/encrypted_data.rs create mode 100644 src-tauri/src/api/fee.rs create mode 100644 src-tauri/src/api/tokens.rs create mode 100644 src-tauri/src/api/user.rs create mode 100644 src-tauri/src/helpers.rs create mode 100644 src-tauri/src/helpers/upgrade.rs create mode 100644 src-tauri/src/helpers/utils.rs create mode 100644 src-tauri/src/helpers/validation.rs create mode 100644 src-tauri/src/lib.rs create mode 100644 src-tauri/src/main.rs create mode 100644 src-tauri/src/models.rs create mode 100644 src-tauri/src/models/account.rs create mode 100644 src-tauri/src/models/auth.rs create mode 100644 src-tauri/src/models/event.rs create mode 100644 src-tauri/src/models/event_payloads.rs create mode 100644 src-tauri/src/models/pointers.rs create mode 100644 src-tauri/src/models/pointers/deployment.rs create mode 100644 src-tauri/src/models/pointers/message.rs create mode 100644 src-tauri/src/models/pointers/record.rs create mode 100644 src-tauri/src/models/pointers/transaction.rs create mode 100644 src-tauri/src/models/pointers/transition.rs create mode 100644 src-tauri/src/models/storage/encryption.rs create mode 100644 src-tauri/src/models/storage/languages.rs create mode 100644 src-tauri/src/models/storage/mod.rs create mode 100644 src-tauri/src/models/storage/persistent.rs create mode 100644 src-tauri/src/models/transfer.rs create mode 100644 src-tauri/src/models/wallet.rs create mode 100644 src-tauri/src/models/wallet_connect.rs create mode 100644 src-tauri/src/models/wallet_connect/balance.rs create mode 100644 src-tauri/src/models/wallet_connect/create_event.rs create mode 100644 src-tauri/src/models/wallet_connect/decrypt.rs create mode 100644 src-tauri/src/models/wallet_connect/deploy.rs create mode 100644 src-tauri/src/models/wallet_connect/get_event.rs create mode 100644 src-tauri/src/models/wallet_connect/records.rs create mode 100644 src-tauri/src/models/wallet_connect/sign.rs create mode 100644 src-tauri/src/services.rs create mode 100644 src-tauri/src/services/README.md create mode 100644 src-tauri/src/services/account.rs create mode 100644 src-tauri/src/services/account/generation.rs create mode 100644 src-tauri/src/services/account/key_management.rs create mode 100644 src-tauri/src/services/account/key_management/android.rs create mode 100644 src-tauri/src/services/account/key_management/desktop.rs create mode 100644 src-tauri/src/services/account/key_management/iOS.rs create mode 100644 src-tauri/src/services/account/key_management/key_controller.rs create mode 100644 src-tauri/src/services/account/phrase_recovery.rs create mode 100644 src-tauri/src/services/account/shard_recovery.rs create mode 100644 src-tauri/src/services/account/utils.rs create mode 100644 src-tauri/src/services/authentication.rs create mode 100644 src-tauri/src/services/authentication/android.rs create mode 100644 src-tauri/src/services/authentication/ios.rs create mode 100644 src-tauri/src/services/authentication/session.rs create mode 100644 src-tauri/src/services/local_storage.rs create mode 100644 src-tauri/src/services/local_storage/encrypted_data.rs create mode 100644 src-tauri/src/services/local_storage/persistent_storage.rs create mode 100644 src-tauri/src/services/local_storage/session.rs create mode 100644 src-tauri/src/services/local_storage/session/password.rs create mode 100644 src-tauri/src/services/local_storage/session/view.rs create mode 100644 src-tauri/src/services/local_storage/storage_api.rs create mode 100644 src-tauri/src/services/local_storage/storage_api/deployment.rs create mode 100644 src-tauri/src/services/local_storage/storage_api/event.rs create mode 100644 src-tauri/src/services/local_storage/storage_api/records.rs create mode 100644 src-tauri/src/services/local_storage/storage_api/transaction.rs create mode 100644 src-tauri/src/services/local_storage/storage_api/transition.rs create mode 100644 src-tauri/src/services/local_storage/tokens.rs create mode 100644 src-tauri/src/services/local_storage/utils.rs create mode 100644 src-tauri/src/services/record_handling.rs create mode 100644 src-tauri/src/services/record_handling/decrypt_transition.rs create mode 100644 src-tauri/src/services/record_handling/docs.md create mode 100644 src-tauri/src/services/record_handling/records.rs create mode 100644 src-tauri/src/services/record_handling/sync.rs create mode 100644 src-tauri/src/services/record_handling/transfer.rs create mode 100644 src-tauri/src/services/record_handling/utils.rs create mode 100644 src-tauri/src/services/records.rs create mode 100644 src-tauri/src/services/wallet_connect_api.rs create mode 100644 src-tauri/tauri.conf.json create mode 100644 src-tauri/tauri.windows.conf.json diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6e42216e..926fc27b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,4 +18,4 @@ repos: - id: fmt stages: - "pre-commit" - args: ["--manifest-path", "backend/Cargo.toml", "--all", "--"] + args: ["--manifest-path", "src-tauri/Cargo.toml", "--all", "--"] diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore new file mode 100644 index 00000000..91eab81d --- /dev/null +++ b/src-tauri/.gitignore @@ -0,0 +1,4 @@ +gen/** +target/** +.cargo/** +.env diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock new file mode 100644 index 00000000..b6f47209 --- /dev/null +++ b/src-tauri/Cargo.lock @@ -0,0 +1,7561 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher 0.3.0", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes 0.8.3", + "cipher 0.4.4", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +dependencies = [ + "memchr", +] + +[[package]] +name = "aleo-std" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3aa6ad1a3bb96698e7e8d8e42a6f2fda3b8611a43aab4d5effb921f18798833" +dependencies = [ + "aleo-std-cpu", + "aleo-std-profiler", + "aleo-std-storage", + "aleo-std-time", + "aleo-std-timed", + "aleo-std-timer", +] + +[[package]] +name = "aleo-std-cpu" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7527351aa675fdbe6a1902de3cf913ff7d50ccd6822f1562be374bdd85eaefb8" + +[[package]] +name = "aleo-std-profiler" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf055ddb2f54fa86394d19d87e7956df2f3cafff489fc14c0f48f2f80664c3d" + +[[package]] +name = "aleo-std-storage" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503e2538d5158b869bc9c30c9754f9a23f4210987008014a9f118db99f22c217" +dependencies = [ + "dirs 4.0.0", +] + +[[package]] +name = "aleo-std-time" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f2a841f04c2eaeb5a95312e5201a9e4b7c95b64ca99870d6bd2e2376df540a" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "aleo-std-timed" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6118baab6285accf088b31d5ea5029c37bbf9d98e62b4d8720a0a5a66bc2e427" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "aleo-std-timer" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e4f181fc1a372e8ceff89612e5c9b13f72bff5b066da9f8d6827ae65af492c4" + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[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 = "anstream" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "app_dirs2" +version = "2.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e7b35733e3a8c1ccb90385088dd5b6eaa61325cb4d1ad56e683b5224ff352e" +dependencies = [ + "jni", + "ndk-context", + "winapi 0.3.9", + "xdg", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "async-broadcast" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" +dependencies = [ + "event-listener", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" +dependencies = [ + "async-lock", + "async-task", + "concurrent-queue", + "fastrand 1.9.0", + "futures-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock", + "autocfg", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite", + "log", + "parking", + "polling", + "rustix 0.37.24", + "slab", + "socket2 0.4.9", + "waker-fn", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-process" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" +dependencies = [ + "async-io", + "async-lock", + "autocfg", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix 0.37.24", + "signal-hook", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-recursion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "async-task" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" + +[[package]] +name = "async-trait" +version = "0.1.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2d0f03b3640e3a630367e40c468cb7f309529c708ed1d88597047b0e7c6ef7" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "atk" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4af014b17dd80e8af9fa689b2d4a211ddba6eb583c1622f35d0cb543f6b17e4" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atomic-waker" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "avail-common" +version = "0.5.0" +source = "git+https://github.com/availx/avail-lib?tag=v0.5.0#9db153348a031d5a94c674fa1187182b5d65ca4e" +dependencies = [ + "aes-gcm", + "app_dirs2", + "bincode", + "bs58", + "chrono", + "duration-str", + "hex", + "jni", + "keyring", + "once_cell", + "rand 0.8.5", + "reqwest", + "rusqlite", + "rust-argon2", + "security-framework 2.9.1", + "security-framework-sys 2.9.0", + "serde", + "serde_json", + "snarkvm", + "tokio", + "tracing", + "ureq", + "url", + "uuid", +] + +[[package]] +name = "avail_wallet" +version = "0.0.1" +dependencies = [ + "app_dirs2", + "avail-common", + "bs58", + "chrono", + "core-foundation", + "dirs 5.0.1", + "dotenv", + "fix-path-env", + "futures", + "jni", + "keyring", + "libc", + "log", + "ndk-context", + "once_cell", + "openssl", + "rand 0.8.5", + "rayon", + "rstest", + "rusqlite", + "security-framework 2.9.1", + "security-framework-sys 2.9.0", + "serde", + "serde_json", + "snarkvm", + "ssss", + "tauri", + "tauri-build", + "tauri-plugin-deep-link", + "tauri-plugin-http", + "tauri-plugin-updater", + "tid-rs", + "tiny-bip39", + "tokio", + "ureq", + "uuid", + "whoami", + "zeroize", +] + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +dependencies = [ + "serde", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq 0.3.0", +] + +[[package]] +name = "blake2s_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq 0.3.0", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[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 = "block-modes" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" +dependencies = [ + "block-padding", + "cipher 0.3.0", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "blocking" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "atomic-waker", + "fastrand 1.9.0", + "futures-lite", + "log", +] + +[[package]] +name = "brotli" +version = "3.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +dependencies = [ + "serde", +] + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.4.0", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cargo_toml" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a969e13a7589e9e3e4207e153bae624ade2b5622fb4684a4923b23ec3d57719" +dependencies = [ + "serde", + "toml 0.8.2", +] + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cfg_aliases" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e53693616d3075149f4ead59bdeecd204ac6b8192d8969757601b74bddf00f" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.48.5", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "4.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824956d0dca8334758a5b7f7e50518d66ea319330cbceedcf76905c2f6ab30e3" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122ec64120a49b4563ccaedcbea7818d069ed8e9aa6d829b82d8a4128936b2ab" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +dependencies = [ + "heck", + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "clap_lex" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" + +[[package]] +name = "cocoa" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types 0.5.0", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "colored" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +dependencies = [ + "is-terminal", + "lazy_static", + "windows-sys 0.48.0", +] + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.45.0", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa" +dependencies = [ + "cookie", + "idna 0.2.3", + "log", + "publicsuffix", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "core-graphics" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset 0.9.0", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa 0.4.8", + "matches", + "phf 0.8.0", + "proc-macro2", + "quote 1.0.35", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "ctor" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" +dependencies = [ + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher 0.4.4", +] + +[[package]] +name = "curl" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2 0.4.9", + "winapi 0.3.9", +] + +[[package]] +name = "curl-sys" +version = "0.4.66+curl-8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70c44a72e830f0e40ad90dda8a6ab6ed6314d39776599a58a2e5e37fbc6db5b9" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "windows-sys 0.48.0", +] + +[[package]] +name = "darling" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote 1.0.35", + "strsim", + "syn 2.0.49", +] + +[[package]] +name = "darling_macro" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" +dependencies = [ + "darling_core", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "data-url" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote 1.0.35", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys 0.3.7", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi 0.3.9", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi 0.3.9", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.7.4", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "drm" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde" +dependencies = [ + "bitflags 2.4.0", + "bytemuck", + "drm-ffi", + "drm-fourcc", + "rustix 0.38.31", +] + +[[package]] +name = "drm-ffi" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41334f8405792483e32ad05fbb9c5680ff4e84491883d2947a4757dc54cb2ac6" +dependencies = [ + "drm-sys", + "rustix 0.38.31", +] + +[[package]] +name = "drm-fourcc" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" + +[[package]] +name = "drm-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d09ff881f92f118b11105ba5e34ff8f4adf27b30dae8f12e28c193af1c83176" +dependencies = [ + "libc", + "linux-raw-sys 0.6.4", +] + +[[package]] +name = "dtoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d09067bfacaa79114679b279d7f5885b53295b1e2cfb4e79c8e4bd3d633169" + +[[package]] +name = "dtoa-short" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "duration-str" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e172e85f305d6a442b250bf40667ffcb91a24f52c9a1ca59e2fa991ac9b7790" +dependencies = [ + "chrono", + "nom", + "rust_decimal", + "serde", + "thiserror", + "time", +] + +[[package]] +name = "dyn-clone" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "embed-resource" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80663502655af01a2902dff3f06869330782267924bf1788410b74edcd93770a" +dependencies = [ + "cc", + "rustc_version", + "toml 0.7.4", + "vswhom", + "winreg 0.11.0", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum_index" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5532bdea562e7be83060c36185eecccba82fe16729d2eaad2891d65417656dd" + +[[package]] +name = "enum_index_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ab22c8085548bf06190113dca556e149ecdbb05ae5b972a2b9899f26b944ee4" +dependencies = [ + "quote 0.3.15", + "syn 0.11.11", +] + +[[package]] +name = "enumflags2" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5998b4f30320c9d93aed72f63af821bfdac50465b75428fce77b48ec482c3939" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset 0.9.0", + "rustc_version", +] + +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", +] + +[[package]] +name = "fix-path-env" +version = "0.0.0" +source = "git+https://github.com/tauri-apps/fix-path-env-rs#8481725b7ebfc56cdb052d522517421242eac36b" +dependencies = [ + "strip-ansi-escapes", + "thiserror", +] + +[[package]] +name = "flate2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5ba081bdef3b75ebcdbfc953699ed2d7417d6bd853347a42a37d76406a33646" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90fbf5c033c65d93792192a49a8efb5bb1e640c419682a58bb96f5ae77f3d4a" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2ea8a4909d530f79921290389cbd7c34cb9d623bfe970eaae65ca5f9cd9cce" +dependencies = [ + "gdk", + "gdkx11-sys", + "gio", + "glib", + "libc", + "x11", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee8f00f4ee46cad2939b8990f5c70c94ff882c3028f3cc5abf950fa4ab53043" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows 0.48.0", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets 0.48.5", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getset" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "ghash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi 0.3.9", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.4.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck", + "proc-macro-crate 2.0.1", + "proc-macro-error", + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93c4f5e0e20b60e10631a5f06da7fe3dda744b05ad0ea71fee2f47adf865890c" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6063efb63db582968fb7df72e1ae68aa6360dcfb0a75143f34fc7d616bad75e" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "h2" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 1.9.3", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.0", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.6", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa 1.0.6", + "pin-project-lite", + "socket2 0.4.9", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows 0.48.0", +] + +[[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 = "ico" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae" +dependencies = [ + "byteorder", + "png", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "image" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-rational", + "num-traits", +] + +[[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.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", + "rayon", + "serde", +] + +[[package]] +name = "indicatif" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "infer" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199" +dependencies = [ + "cfb", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix 0.38.31", + "windows-sys 0.48.0", +] + +[[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 = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "javascriptcore-rs" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir 2.3.3", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ff1e1486799e3f64129f8ccad108b38290df9cd7015cd31bed17239f0789d6" +dependencies = [ + "serde", + "serde_json", + "thiserror", + "treediff", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.4.0", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "keyring" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9549a129bd08149e0a71b2d1ce2729780d47127991bfd0a78cc1df697ec72492" +dependencies = [ + "byteorder", + "lazy_static", + "linux-keyutils", + "secret-service", + "security-framework 2.9.2", + "winapi 0.3.9", +] + +[[package]] +name = "kuchikiki" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" +dependencies = [ + "cssparser", + "html5ever", + "indexmap 1.9.3", + "matches", + "selectors", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading 0.7.4", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi 0.3.9", +] + +[[package]] +name = "libloading" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "line-wrap" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" +dependencies = [ + "safemem", +] + +[[package]] +name = "linux-keyutils" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f27bb67f6dd1d0bb5ab582868e4f65052e58da6401188a08f0da09cf512b84b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "linux-raw-sys" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0b5399f6804fbab912acbd8878ed3532d506b7c951b8f9f164ef90fef39e3f4" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf 0.10.1", + "phf_codegen 0.10.0", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "minisign-verify" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "933dca44d65cdd53b355d0b73d380a2ff5da71f87f036053188bf1eab6a19881" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + +[[package]] +name = "muda" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e406691fa7749604bbc7964bde28a300572d52621bb84540f6907c0f8fe08737" +dependencies = [ + "cocoa", + "crossbeam-channel", + "gtk", + "keyboard-types", + "objc", + "once_cell", + "png", + "serde", + "thiserror", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.9.2", + "security-framework-sys 2.9.1", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +dependencies = [ + "bitflags 1.3.2", + "jni-sys", + "ndk-sys", + "num_enum", + "raw-window-handle 0.5.2", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.4.1+23.1.7779620" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", +] + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi 0.3.9", +] + +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "num-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec", + "itoa 1.0.6", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl" +version = "0.10.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +dependencies = [ + "bitflags 2.4.0", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-src" +version = "300.1.5+3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "559068e4c12950d7dcaa1857a61725c0d38d4fc03ff8e070ab31a75d6e316491" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_macros 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared 0.10.0", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros 0.11.2", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "plist" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdc0001cfea3db57a2e24bc0d818e9e20e554b5f97fabb9bc231dc240269ae06" +dependencies = [ + "base64", + "indexmap 1.9.3", + "line-wrap", + "quick-xml 0.29.0", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polyval" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.10", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +dependencies = [ + "toml_datetime", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] +name = "publicsuffix" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +dependencies = [ + "idna 0.3.0", + "psl-types", +] + +[[package]] +name = "quick-xml" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11bafc859c6815fbaffbbbf4229ecb767ac913fecb27f9ad4343662e9ef099ea" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[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 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.10", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "raw-window-handle" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.10", + "redox_syscall 0.2.16", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.3.7", + "regex-syntax 0.7.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "relative-path" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" + +[[package]] +name = "reqwest" +version = "0.11.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +dependencies = [ + "base64", + "bytes", + "cookie", + "cookie_store", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "winreg 0.50.0", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi 0.3.9", +] + +[[package]] +name = "rstest" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97eeab2f3c0a199bc4be135c36c924b6590b88c377d416494288c14f2db30199" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" +dependencies = [ + "cfg-if", + "glob", + "proc-macro2", + "quote 1.0.35", + "regex", + "relative-path", + "rustc_version", + "syn 2.0.49", + "unicode-ident", +] + +[[package]] +name = "rusqlite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" +dependencies = [ + "bitflags 2.4.0", + "chrono", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[package]] +name = "rust-argon2" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5885493fdf0be6cdff808d1533ce878d21cfa49c7086fa00c66355cd9141bfc" +dependencies = [ + "base64", + "blake2b_simd", + "constant_time_eq 0.3.0", + "crossbeam-utils", +] + +[[package]] +name = "rust_decimal" +version = "1.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c4216490d5a413bc6d10fa4742bd7d4955941d062c0ef873141d6b0e7b30fd" +dependencies = [ + "arrayvec", + "num-traits", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4279d76516df406a8bd37e7dff53fd37d1a093f997a3c34a5c21658c126db06d" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.6", + "sct", +] + +[[package]] +name = "rustls-webpki" +version = "0.100.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "same-file" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" +dependencies = [ + "kernel32-sys", + "winapi 0.2.8", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secret-service" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da1a5ad4d28c03536f82f77d9f36603f5e37d8869ac98f0a750d5b5686d8d95" +dependencies = [ + "aes 0.7.5", + "block-modes", + "futures-util", + "generic-array", + "hkdf", + "num", + "once_cell", + "rand 0.8.5", + "serde", + "sha2", + "zbus", +] + +[[package]] +name = "security-framework" +version = "2.9.1" +source = "git+https://github.com/AvailX/rust-security-framework#6bf8af0f251eb9a8181dee97ecb41a1bc45145b7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys 2.9.0", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys 2.9.1", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.0" +source = "git+https://github.com/AvailX/rust-security-framework#6bf8af0f251eb9a8181dee97ecb41a1bc45145b7" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "selectors" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +dependencies = [ + "bitflags 1.3.2", + "cssparser", + "derive_more", + "fxhash", + "log", + "matches", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc", + "smallvec", + "thin-slice", +] + +[[package]] +name = "self-replace" +version = "1.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525db198616b2bcd0f245daf7bfd8130222f7ee6af9ff9984c19a61bf1160c55" +dependencies = [ + "fastrand 1.9.0", + "tempfile", + "windows-sys 0.48.0", +] + +[[package]] +name = "self_update" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b3c585a1ced6b97ac13bd5e56f66559e5a75f477da5913f70df98e114518446" +dependencies = [ + "hyper", + "indicatif", + "log", + "quick-xml 0.23.1", + "regex", + "reqwest", + "self-replace", + "semver", + "serde_json", + "tempfile", + "urlencoding", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +dependencies = [ + "indexmap 2.0.0", + "itoa 1.0.6", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0a21fba416426ac927b1691996e82079f8b6156e920c85345f135b2e9ba2de" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.6", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "serde", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070" +dependencies = [ + "darling", + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "servo_arc" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "smol_str" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +dependencies = [ + "serde", +] + +[[package]] +name = "snarkvm" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c5327b3b6f3f6f90f267287480585fdefe430343567d928b7faf410e86c8a4" +dependencies = [ + "anstyle", + "anyhow", + "clap", + "colored", + "dotenvy", + "indexmap 2.0.0", + "num-format", + "once_cell", + "parking_lot", + "rand 0.8.5", + "rayon", + "self_update", + "serde_json", + "snarkvm-circuit", + "snarkvm-console", + "snarkvm-ledger", + "snarkvm-parameters", + "snarkvm-synthesizer", + "snarkvm-utilities", + "thiserror", + "ureq", + "walkdir 2.3.3", +] + +[[package]] +name = "snarkvm-algorithms" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26669ac56886463e8487bce6d14d72910218b33270fac9cc6fe43bbe350cc13c" +dependencies = [ + "aleo-std", + "anyhow", + "blake2", + "cfg-if", + "fxhash", + "hashbrown 0.14.0", + "hex", + "indexmap 2.0.0", + "itertools", + "num-traits", + "parking_lot", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "rayon", + "serde", + "sha2", + "smallvec", + "snarkvm-curves", + "snarkvm-fields", + "snarkvm-parameters", + "snarkvm-utilities", + "thiserror", +] + +[[package]] +name = "snarkvm-circuit" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b489ec6a10b47a601f6bbdfbe09e50aa02f108993764304c61b19b1cd5dd86ae" +dependencies = [ + "snarkvm-circuit-account", + "snarkvm-circuit-algorithms", + "snarkvm-circuit-collections", + "snarkvm-circuit-environment", + "snarkvm-circuit-network", + "snarkvm-circuit-program", + "snarkvm-circuit-types", +] + +[[package]] +name = "snarkvm-circuit-account" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04de0f281e8cb174db02a5aa6c8a799368e223c65b4dfa98d608832ca37c24cb" +dependencies = [ + "snarkvm-circuit-algorithms", + "snarkvm-circuit-network", + "snarkvm-circuit-types", + "snarkvm-console-account", +] + +[[package]] +name = "snarkvm-circuit-algorithms" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e48e2584ed51528640a1d2290baf12b1df48a1dae6fdda23b7654d7fdc7c5d4" +dependencies = [ + "snarkvm-circuit-types", + "snarkvm-console-algorithms", + "snarkvm-fields", +] + +[[package]] +name = "snarkvm-circuit-collections" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c84f47b49192d8db8468ebe311e05e8db60f7c265f7fef39e50e419487b2825a" +dependencies = [ + "snarkvm-circuit-algorithms", + "snarkvm-circuit-types", + "snarkvm-console-collections", +] + +[[package]] +name = "snarkvm-circuit-environment" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff28494552a816376c48403f3072fea6707040a6a285ab3de1000220a31b2354" +dependencies = [ + "indexmap 2.0.0", + "itertools", + "nom", + "num-traits", + "once_cell", + "snarkvm-algorithms", + "snarkvm-circuit-environment-witness", + "snarkvm-console-network", + "snarkvm-curves", + "snarkvm-fields", + "snarkvm-utilities", +] + +[[package]] +name = "snarkvm-circuit-environment-witness" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76645b2e4b9d0e43d1cb6058daf7345b07de9345cd04da6ef04efdf40b44ae47" + +[[package]] +name = "snarkvm-circuit-network" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df782e802eecf25c299b4cd597d06e53597071640a5493c89e4d6aed91f66d2" +dependencies = [ + "snarkvm-circuit-algorithms", + "snarkvm-circuit-collections", + "snarkvm-circuit-types", + "snarkvm-console-network", +] + +[[package]] +name = "snarkvm-circuit-program" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e71f5ad7de2ca4d4b8e14105ca64fae07f4bcff4594b2e3f7bfbb4589ca3bc8e" +dependencies = [ + "paste", + "snarkvm-circuit-account", + "snarkvm-circuit-algorithms", + "snarkvm-circuit-collections", + "snarkvm-circuit-network", + "snarkvm-circuit-types", + "snarkvm-console-program", + "snarkvm-utilities", +] + +[[package]] +name = "snarkvm-circuit-types" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c4a378bf31550b077385594761a22d22249a661bedd0aa228fbf695c457d86" +dependencies = [ + "snarkvm-circuit-environment", + "snarkvm-circuit-types-address", + "snarkvm-circuit-types-boolean", + "snarkvm-circuit-types-field", + "snarkvm-circuit-types-group", + "snarkvm-circuit-types-integers", + "snarkvm-circuit-types-scalar", + "snarkvm-circuit-types-string", +] + +[[package]] +name = "snarkvm-circuit-types-address" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf8ad07c0f70c9893389c9e6d1a24d152dd051e65c77f57d6ffeb59ce47a1cd" +dependencies = [ + "snarkvm-circuit-environment", + "snarkvm-circuit-types-boolean", + "snarkvm-circuit-types-field", + "snarkvm-circuit-types-group", + "snarkvm-circuit-types-scalar", + "snarkvm-console-types-address", +] + +[[package]] +name = "snarkvm-circuit-types-boolean" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9d81a0d28d89c599cf6b9a951bd1a365ba5bca7bab7c7c95ba9e5881ee3244" +dependencies = [ + "snarkvm-circuit-environment", + "snarkvm-console-types-boolean", +] + +[[package]] +name = "snarkvm-circuit-types-field" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c77c1d6412abe2bc5e1c8b6e6f3461d2d19a041836ea24bdcd3e24c308b72a1" +dependencies = [ + "snarkvm-circuit-environment", + "snarkvm-circuit-types-boolean", + "snarkvm-console-types-field", +] + +[[package]] +name = "snarkvm-circuit-types-group" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "191d7a14dad5fcb548ca367c43cdbd0560218c3dfb709a8fab934b50f8054829" +dependencies = [ + "snarkvm-circuit-environment", + "snarkvm-circuit-types-boolean", + "snarkvm-circuit-types-field", + "snarkvm-circuit-types-scalar", + "snarkvm-console-types-group", +] + +[[package]] +name = "snarkvm-circuit-types-integers" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5770d31bfa0c0732a1f03e786ac8adf12045e8200d47a496a6f79e2da97207b1" +dependencies = [ + "snarkvm-circuit-environment", + "snarkvm-circuit-types-boolean", + "snarkvm-circuit-types-field", + "snarkvm-circuit-types-scalar", + "snarkvm-console-types-integers", +] + +[[package]] +name = "snarkvm-circuit-types-scalar" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "019520127c534b60e7660e8d95881e8a075328e9ef0b6dfa5765e81ef72ef021" +dependencies = [ + "snarkvm-circuit-environment", + "snarkvm-circuit-types-boolean", + "snarkvm-circuit-types-field", + "snarkvm-console-types-scalar", +] + +[[package]] +name = "snarkvm-circuit-types-string" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd3632f0c72f767f3fa8d9d7ae954f70a249e33ac1ee377fdf294aec042c1f5" +dependencies = [ + "snarkvm-circuit-environment", + "snarkvm-circuit-types-boolean", + "snarkvm-circuit-types-field", + "snarkvm-circuit-types-integers", + "snarkvm-console-types-string", +] + +[[package]] +name = "snarkvm-console" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1589ee1c45788e798a27e5c6c9e77c407fc2fb23b8844430c8328c4530acf774" +dependencies = [ + "snarkvm-console-account", + "snarkvm-console-algorithms", + "snarkvm-console-collections", + "snarkvm-console-network", + "snarkvm-console-program", + "snarkvm-console-types", +] + +[[package]] +name = "snarkvm-console-account" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c63fffc49eb78d0187d4dab2cbc41ba816361a6682ffbfcc334d36463c767148" +dependencies = [ + "bs58", + "snarkvm-console-network", + "snarkvm-console-types", + "zeroize", +] + +[[package]] +name = "snarkvm-console-algorithms" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78de991dce272f0236573b8a759da19527f136d6f45031b2d059f67ef9ac1b02" +dependencies = [ + "blake2s_simd", + "smallvec", + "snarkvm-console-types", + "snarkvm-fields", + "snarkvm-utilities", + "tiny-keccak", +] + +[[package]] +name = "snarkvm-console-collections" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "344433096a532bb3787c5723c4db96a618f04186e8197cc2dc08437ef1f881b3" +dependencies = [ + "aleo-std", + "rayon", + "snarkvm-console-algorithms", + "snarkvm-console-types", +] + +[[package]] +name = "snarkvm-console-network" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36771f6bed6abf36eae21f0371d46a0e6c97608b118ee63339edf24ee7faaa53" +dependencies = [ + "anyhow", + "indexmap 2.0.0", + "itertools", + "lazy_static", + "once_cell", + "paste", + "serde", + "snarkvm-algorithms", + "snarkvm-console-algorithms", + "snarkvm-console-collections", + "snarkvm-console-network-environment", + "snarkvm-console-types", + "snarkvm-curves", + "snarkvm-fields", + "snarkvm-parameters", + "snarkvm-utilities", +] + +[[package]] +name = "snarkvm-console-network-environment" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd5ab64dc360d0148579b14a29de6e51c9fa456e7fac51ce944e254df549cad5" +dependencies = [ + "anyhow", + "bech32", + "itertools", + "nom", + "num-traits", + "rand 0.8.5", + "serde", + "snarkvm-curves", + "snarkvm-fields", + "snarkvm-utilities", + "zeroize", +] + +[[package]] +name = "snarkvm-console-program" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223979a6c22c2e25eda6c501668da9df954f9a87a982516b0c982b514766f232" +dependencies = [ + "enum_index", + "enum_index_derive", + "indexmap 2.0.0", + "num-derive 0.4.0", + "num-traits", + "once_cell", + "paste", + "serde_json", + "snarkvm-console-account", + "snarkvm-console-algorithms", + "snarkvm-console-collections", + "snarkvm-console-network", + "snarkvm-console-types", + "snarkvm-utilities", +] + +[[package]] +name = "snarkvm-console-types" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ebb8bdbdd728437c7f5b611cc2a03015c3ae015bfd0618956d81d25b2da4ce2" +dependencies = [ + "snarkvm-console-network-environment", + "snarkvm-console-types-address", + "snarkvm-console-types-boolean", + "snarkvm-console-types-field", + "snarkvm-console-types-group", + "snarkvm-console-types-integers", + "snarkvm-console-types-scalar", + "snarkvm-console-types-string", +] + +[[package]] +name = "snarkvm-console-types-address" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b29ac58056051bbb57a5ef49682d1a3bf482b9f2e442307fb081f4a5ca1b2f83" +dependencies = [ + "snarkvm-console-network-environment", + "snarkvm-console-types-boolean", + "snarkvm-console-types-field", + "snarkvm-console-types-group", +] + +[[package]] +name = "snarkvm-console-types-boolean" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e935a2a68edc8b5be8a0d211dc52c9cca95cb8a343ca102cb73cce5ef03cdff" +dependencies = [ + "snarkvm-console-network-environment", +] + +[[package]] +name = "snarkvm-console-types-field" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "475b3857782cbb98ed8191a69e96f50726fdfc02769b6793eef9af1f3f76e2f4" +dependencies = [ + "snarkvm-console-network-environment", + "snarkvm-console-types-boolean", + "zeroize", +] + +[[package]] +name = "snarkvm-console-types-group" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a46244de03e589b46dbcb29672f34923d541e58d91801764e8c9da3bcc9ee7b7" +dependencies = [ + "snarkvm-console-network-environment", + "snarkvm-console-types-boolean", + "snarkvm-console-types-field", + "snarkvm-console-types-scalar", +] + +[[package]] +name = "snarkvm-console-types-integers" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9bee7bf0b1d3295cebeada300985bc382a91771159b33f1c43e9627e98b37ec" +dependencies = [ + "snarkvm-console-network-environment", + "snarkvm-console-types-boolean", + "snarkvm-console-types-field", + "snarkvm-console-types-scalar", +] + +[[package]] +name = "snarkvm-console-types-scalar" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55a1e523a27f49a4db21eba6514f9f12dd739a30d440cdb4e4d93a4ae6e2d368" +dependencies = [ + "snarkvm-console-network-environment", + "snarkvm-console-types-boolean", + "snarkvm-console-types-field", + "zeroize", +] + +[[package]] +name = "snarkvm-console-types-string" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595994b88e0c0b91e20c4f810e2b70d2c6aac8d92c016ca2fd6db38647a5f28f" +dependencies = [ + "snarkvm-console-network-environment", + "snarkvm-console-types-boolean", + "snarkvm-console-types-field", + "snarkvm-console-types-integers", +] + +[[package]] +name = "snarkvm-curves" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd462a08bd74e09b7bc2c97e56d6706ae44f81ccbd52a16aed0d303a9f794e8" +dependencies = [ + "rand 0.8.5", + "rayon", + "rustc_version", + "serde", + "snarkvm-fields", + "snarkvm-utilities", + "thiserror", +] + +[[package]] +name = "snarkvm-fields" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8767f827e60eb2e26e7fa36b7b19e75096765c6ec5cf659073a28de60a6e269" +dependencies = [ + "aleo-std", + "anyhow", + "itertools", + "num-traits", + "rand 0.8.5", + "rayon", + "serde", + "snarkvm-utilities", + "thiserror", + "zeroize", +] + +[[package]] +name = "snarkvm-ledger" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc018c528b1637aad00041ff54b44eeba6f0507820bcb7236f64b760ace323fa" +dependencies = [ + "aleo-std", + "anyhow", + "indexmap 2.0.0", + "parking_lot", + "rand 0.8.5", + "rayon", + "snarkvm-console", + "snarkvm-ledger-authority", + "snarkvm-ledger-block", + "snarkvm-ledger-coinbase", + "snarkvm-ledger-committee", + "snarkvm-ledger-narwhal", + "snarkvm-ledger-query", + "snarkvm-ledger-store", + "snarkvm-synthesizer", + "time", + "tracing", +] + +[[package]] +name = "snarkvm-ledger-authority" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2b52a1f9fb06498c0815e8937bd6f5f0b270e2b065c887fc010c247f70a53cf" +dependencies = [ + "anyhow", + "rand 0.8.5", + "serde_json", + "snarkvm-console", + "snarkvm-ledger-narwhal-subdag", +] + +[[package]] +name = "snarkvm-ledger-block" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e3a43fcd45a835aeebaa140acd73d75d1fe138eaf1ebb985ab17856eb4b896" +dependencies = [ + "indexmap 2.0.0", + "rayon", + "serde_json", + "snarkvm-console", + "snarkvm-ledger-authority", + "snarkvm-ledger-coinbase", + "snarkvm-ledger-committee", + "snarkvm-ledger-narwhal-batch-header", + "snarkvm-ledger-narwhal-subdag", + "snarkvm-ledger-narwhal-transmission-id", + "snarkvm-synthesizer-program", + "snarkvm-synthesizer-snark", +] + +[[package]] +name = "snarkvm-ledger-coinbase" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83981c236674369fbfdb03be133628ec512ceb3c47277f5dc90983f39d37de94" +dependencies = [ + "aleo-std", + "anyhow", + "bincode", + "blake2", + "indexmap 2.0.0", + "rayon", + "serde_json", + "snarkvm-algorithms", + "snarkvm-console", + "snarkvm-curves", + "snarkvm-fields", + "snarkvm-synthesizer-snark", + "snarkvm-utilities", +] + +[[package]] +name = "snarkvm-ledger-committee" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bc2b8d00e9ab5de46dc071e3598285d8cf795d695172c0de17f78f37998c13" +dependencies = [ + "indexmap 2.0.0", + "serde_json", + "snarkvm-console", +] + +[[package]] +name = "snarkvm-ledger-narwhal" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64afd92dbbb468baca5eb7632542293d50ab94de0314045ddf9c2d1f97b8181b" +dependencies = [ + "snarkvm-ledger-narwhal-batch-certificate", + "snarkvm-ledger-narwhal-batch-header", + "snarkvm-ledger-narwhal-data", + "snarkvm-ledger-narwhal-subdag", + "snarkvm-ledger-narwhal-transmission", + "snarkvm-ledger-narwhal-transmission-id", +] + +[[package]] +name = "snarkvm-ledger-narwhal-batch-certificate" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae7f97eb5229a0667cd7cc4b69b118912c6e5544609d710c9f85f9fd6c31441e" +dependencies = [ + "indexmap 2.0.0", + "rayon", + "serde_json", + "snarkvm-console", + "snarkvm-ledger-narwhal-batch-header", + "snarkvm-ledger-narwhal-transmission-id", +] + +[[package]] +name = "snarkvm-ledger-narwhal-batch-header" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b36228488081fe641c36ad8db890d903df4b19fb9720891f1ca172a0d1bb39e" +dependencies = [ + "indexmap 2.0.0", + "serde_json", + "snarkvm-console", + "snarkvm-ledger-narwhal-transmission-id", +] + +[[package]] +name = "snarkvm-ledger-narwhal-data" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15315726d409003433d7e56dcedab7e86c9feb0dcaa3979966595ac7e30ec5ab" +dependencies = [ + "bytes", + "serde_json", + "snarkvm-console", + "tokio", +] + +[[package]] +name = "snarkvm-ledger-narwhal-subdag" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb2b721d792dc0a13a1b19de25f1cb3a5b8feaa9796005653b6d2278a6a7e78" +dependencies = [ + "indexmap 2.0.0", + "rayon", + "serde_json", + "snarkvm-console", + "snarkvm-ledger-narwhal-batch-certificate", + "snarkvm-ledger-narwhal-batch-header", + "snarkvm-ledger-narwhal-transmission-id", +] + +[[package]] +name = "snarkvm-ledger-narwhal-transmission" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1670202f2a6897e14327ecc41613f64ecf3020628e448f67d1787615e11c59" +dependencies = [ + "bytes", + "serde_json", + "snarkvm-console", + "snarkvm-ledger-block", + "snarkvm-ledger-coinbase", + "snarkvm-ledger-narwhal-data", +] + +[[package]] +name = "snarkvm-ledger-narwhal-transmission-id" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126131b95a5506266aeea28952666ae10e6e91b9d272207d83ff3c10847b8d85" +dependencies = [ + "snarkvm-console", + "snarkvm-ledger-coinbase", +] + +[[package]] +name = "snarkvm-ledger-query" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7486798046553f092123c4f228ac4e6dd98fbffa313b32d1f20e619d633fbd7b" +dependencies = [ + "async-trait", + "reqwest", + "snarkvm-console", + "snarkvm-ledger-store", + "snarkvm-synthesizer-program", + "ureq", +] + +[[package]] +name = "snarkvm-ledger-store" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99a5d648ec1a58194545393b1e3c0120dbcc4407b0f3cc207a15e680082f7d94" +dependencies = [ + "anyhow", + "bincode", + "indexmap 2.0.0", + "parking_lot", + "rayon", + "serde", + "snarkvm-console", + "snarkvm-ledger-authority", + "snarkvm-ledger-block", + "snarkvm-ledger-coinbase", + "snarkvm-ledger-committee", + "snarkvm-ledger-narwhal-batch-certificate", + "snarkvm-synthesizer-program", + "snarkvm-synthesizer-snark", +] + +[[package]] +name = "snarkvm-parameters" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4d47484bc6c0dfc526becaa37bcb85ba6b61782250b74a104d0ae85243e0caa" +dependencies = [ + "aleo-std", + "anyhow", + "bincode", + "cfg-if", + "colored", + "curl", + "hex", + "indexmap 2.0.0", + "itertools", + "lazy_static", + "parking_lot", + "paste", + "rand 0.8.5", + "serde_json", + "sha2", + "snarkvm-curves", + "snarkvm-utilities", + "thiserror", +] + +[[package]] +name = "snarkvm-synthesizer" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bef8cbc0d9106e43f4ff97235f24c0800f51a3854780a2b7d93abc09ea603cd" +dependencies = [ + "aleo-std", + "anyhow", + "indexmap 2.0.0", + "parking_lot", + "rand 0.8.5", + "rayon", + "snarkvm-algorithms", + "snarkvm-circuit", + "snarkvm-console", + "snarkvm-ledger-block", + "snarkvm-ledger-coinbase", + "snarkvm-ledger-committee", + "snarkvm-ledger-query", + "snarkvm-ledger-store", + "snarkvm-synthesizer-process", + "snarkvm-synthesizer-program", + "snarkvm-synthesizer-snark", + "tracing", +] + +[[package]] +name = "snarkvm-synthesizer-process" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de1ede93f4c3927c0a97db2fb84b7f5e8226e6db6e5b7edb9ba1ae85c3283168" +dependencies = [ + "aleo-std", + "colored", + "indexmap 2.0.0", + "once_cell", + "parking_lot", + "rand 0.8.5", + "rayon", + "serde_json", + "snarkvm-circuit", + "snarkvm-console", + "snarkvm-ledger-block", + "snarkvm-ledger-query", + "snarkvm-ledger-store", + "snarkvm-synthesizer-program", + "snarkvm-synthesizer-snark", + "snarkvm-utilities", +] + +[[package]] +name = "snarkvm-synthesizer-program" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004af9b2cbad5740a72ecf5498cada2909403d0121a2709964967e9887049cd5" +dependencies = [ + "indexmap 2.0.0", + "paste", + "rand 0.8.5", + "rand_chacha 0.3.1", + "serde_json", + "snarkvm-circuit", + "snarkvm-console", +] + +[[package]] +name = "snarkvm-synthesizer-snark" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94eed0d284afc3620935f8772f7f6c5a857e2e9f3a7f0604477a5b09752bb42b" +dependencies = [ + "bincode", + "once_cell", + "serde_json", + "snarkvm-algorithms", + "snarkvm-circuit", + "snarkvm-console", +] + +[[package]] +name = "snarkvm-utilities" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23551bd2b97a7b65c1fa1348ed8269b3e3b39b31da279b978a1d0c8b33bb86b9" +dependencies = [ + "aleo-std", + "anyhow", + "bincode", + "num-bigint", + "num_cpus", + "rand 0.8.5", + "rand_xorshift", + "rayon", + "serde", + "serde_json", + "smol_str", + "snarkvm-utilities-derives", + "thiserror", + "zeroize", +] + +[[package]] +name = "snarkvm-utilities-derives" +version = "0.16.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6cf46ecfdc29202e7f185bbd4d18a5467dc644ed2add9b47234ce559bd8e956" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "socket2" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "softbuffer" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071916a85d1db274b4ed57af3a14afb66bd836ae7f82ebb6f1fd3455107830d9" +dependencies = [ + "as-raw-xcb-connection", + "bytemuck", + "cfg_aliases 0.2.0", + "cocoa", + "core-graphics", + "drm", + "fastrand 2.0.1", + "foreign-types 0.5.0", + "js-sys", + "log", + "memmap2", + "objc", + "raw-window-handle 0.6.0", + "redox_syscall 0.4.1", + "rustix 0.38.31", + "tiny-xlib", + "wasm-bindgen", + "wayland-backend", + "wayland-client", + "wayland-sys", + "web-sys", + "windows-sys 0.52.0", + "x11rb", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "ssss" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc8f7995380537ee49c88de8f05570ac35cb2953e8914017605dfb04c0078486" +dependencies = [ + "anyhow", + "getset", + "num-bigint", + "num-integer", + "num-traits", + "rand 0.8.5", + "rustversion", + "serde", + "thiserror", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "state" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" +dependencies = [ + "loom", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro2", + "quote 1.0.35", +] + +[[package]] +name = "strip-ansi-escapes" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" +dependencies = [ + "vte", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "swift-rs" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bbdb58577b6301f8d17ae2561f32002a5bae056d444e0f69e611e504a276204" +dependencies = [ + "base64", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" +dependencies = [ + "quote 0.3.15", + "synom", + "unicode-xid", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "unicode-ident", +] + +[[package]] +name = "synom" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "system-deps" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml 0.7.4", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa7ba6ee5b8908ba3a62e6a4f3683490ed732fca614cdd3f4c989bba548f9a9" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cocoa", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dispatch", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "image", + "instant", + "jni", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc", + "once_cell", + "parking_lot", + "png", + "raw-window-handle 0.5.2", + "raw-window-handle 0.6.0", + "scopeguard", + "tao-macros", + "unicode-segmentation", + "url", + "windows 0.52.0", + "windows-implement", + "windows-version", + "x11-dl", + "zbus", +] + +[[package]] +name = "tao-macros" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec114582505d158b669b136e6851f85840c109819d77c42bb7c0709f727d18c2" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.12.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" + +[[package]] +name = "tauri" +version = "2.0.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a584d146c38bf174398dee0ec2cdd8f8fce142daee0306c370cf78f050304c60" +dependencies = [ + "anyhow", + "bytes", + "cocoa", + "dirs-next", + "embed_plist", + "futures-util", + "getrandom 0.2.10", + "glob", + "gtk", + "heck", + "http", + "jni", + "libc", + "log", + "mime", + "muda", + "nix", + "objc", + "percent-encoding", + "raw-window-handle 0.5.2", + "reqwest", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "state", + "static_assertions", + "swift-rs", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "thiserror", + "tokio", + "tray-icon", + "url", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows 0.52.0", +] + +[[package]] +name = "tauri-build" +version = "2.0.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314089a25d92a62f33f60d2a19c277f465e9088ee3ea251032ae914d6f2b1ce0" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs-next", + "glob", + "heck", + "json-patch", + "schemars", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "toml 0.8.2", + "walkdir 2.3.3", +] + +[[package]] +name = "tauri-codegen" +version = "2.0.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6ff13874390499976f01decf75103f28e7609abc5c155c6bfb56cf574a5628" +dependencies = [ + "base64", + "brotli", + "ico", + "json-patch", + "plist", + "png", + "proc-macro2", + "quote 1.0.35", + "semver", + "serde", + "serde_json", + "sha2", + "tauri-utils", + "thiserror", + "time", + "url", + "uuid", + "walkdir 2.3.3", +] + +[[package]] +name = "tauri-macros" +version = "2.0.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18707774f70a8ec20dbf653f07d12af1e0d7c1e3a625b7bd5a2cfe72c2b2549b" +dependencies = [ + "heck", + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-plugin" +version = "2.0.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb732726fec855b56e4a238464f1b0c10006f618180ef402ce5f394d840e61b" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars", + "serde", + "serde_json", + "tauri-utils", + "toml 0.8.2", + "walkdir 1.0.7", +] + +[[package]] +name = "tauri-plugin-deep-link" +version = "2.0.0-beta.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c164394707e62f6df52785bc96aa3ee05d15170c7ea534a4fb61ccc26ba0b1" +dependencies = [ + "log", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror", + "url", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.0.0-beta.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd40ca5f99e9a4cbfcbd33de0f0b024caef6475f2652f1707cba72d877398a0" +dependencies = [ + "anyhow", + "glob", + "schemars", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "thiserror", + "url", + "uuid", +] + +[[package]] +name = "tauri-plugin-http" +version = "2.0.0-beta.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e427755fd9229027cc859ae0d19a5d2952a314792c16a25ce50c50eccd4a2db6" +dependencies = [ + "data-url", + "glob", + "http", + "reqwest", + "schemars", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror", + "url", +] + +[[package]] +name = "tauri-plugin-updater" +version = "2.0.0-beta.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca006f95bd7ff80eb2749172c0faf9dc1e27eea20f289a759235753b8a0aabf8" +dependencies = [ + "base64", + "dirs-next", + "flate2", + "futures-util", + "http", + "minisign-verify", + "percent-encoding", + "reqwest", + "semver", + "serde", + "serde_json", + "tar", + "tauri", + "tauri-plugin", + "tempfile", + "thiserror", + "time", + "tokio", + "url", + "zip", +] + +[[package]] +name = "tauri-runtime" +version = "2.0.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d72194de56e885dbd9fd8c493ccf95012e584c928900188da248f9ea4223b23" +dependencies = [ + "gtk", + "http", + "jni", + "raw-window-handle 0.5.2", + "serde", + "serde_json", + "tauri-utils", + "thiserror", + "url", + "windows 0.52.0", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.0.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74a71bd248a7ce857835b1f65845a9de22171e30d8129e018b42961502565efb" +dependencies = [ + "cocoa", + "gtk", + "http", + "jni", + "nix", + "percent-encoding", + "raw-window-handle 0.5.2", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils", + "webkit2gtk", + "webview2-com", + "windows 0.52.0", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "2.0.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7104f0639a1f3a7ebd7aac793be47d7924f569e7c10c6853083529bf9bb3fe6" +dependencies = [ + "brotli", + "cargo_metadata", + "ctor", + "dunce", + "glob", + "heck", + "html5ever", + "infer", + "json-patch", + "kuchikiki", + "log", + "memchr", + "phf 0.11.2", + "proc-macro2", + "quote 1.0.35", + "schemars", + "semver", + "serde", + "serde_json", + "serde_with", + "swift-rs", + "thiserror", + "toml 0.8.2", + "url", + "walkdir 2.3.3", +] + +[[package]] +name = "tauri-winres" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb" +dependencies = [ + "embed-resource", + "toml 0.7.4", +] + +[[package]] +name = "tempfile" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand 2.0.1", + "redox_syscall 0.3.5", + "rustix 0.38.31", + "windows-sys 0.48.0", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "thin-slice" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tid-rs" +version = "0.1.1" +source = "git+https://github.com/Zack-Xb/tid-rs#5cfee74f42b6edb2f3e10f8dbb77fe51be284659" +dependencies = [ + "cc", + "core-foundation", + "num", + "num-derive 0.3.3", + "num-traits", + "parking_lot", + "thiserror", +] + +[[package]] +name = "time" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +dependencies = [ + "itoa 1.0.6", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] + +[[package]] +name = "tiny-bip39" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" +dependencies = [ + "anyhow", + "hmac", + "once_cell", + "pbkdf2", + "rand 0.8.5", + "rustc-hash", + "sha2", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tiny-xlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4098d49269baa034a8d1eae9bd63e9fa532148d772121dace3bcd6a6c98eb6d" +dependencies = [ + "as-raw-xcb-connection", + "ctor", + "libloading 0.8.1", + "tracing", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.4", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.10", +] + +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.20.2", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +dependencies = [ + "indexmap 1.9.3", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.4.7", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.5.34", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tray-icon" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad962d06d2bfd9b2ab4f665fc73b175523b834b1466a294520201c5845145f8" +dependencies = [ + "cocoa", + "core-graphics", + "crossbeam-channel", + "dirs-next", + "libappindicator", + "muda", + "objc", + "once_cell", + "png", + "serde", + "thiserror", + "windows-sys 0.52.0", +] + +[[package]] +name = "treediff" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52984d277bdf2a751072b5df30ec0377febdb02f7696d64c2d7d54630bac4303" +dependencies = [ + "serde_json", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uds_windows" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" +dependencies = [ + "tempfile", + "winapi 0.3.9", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "ureq" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-webpki 0.100.3", + "serde", + "serde_json", + "url", + "webpki-roots", +] + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna 0.4.0", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +dependencies = [ + "getrandom 0.2.10", + "rand 0.8.5", + "serde", + "uuid-macro-internal", +] + +[[package]] +name = "uuid-macro-internal" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e1ba1f333bd65ce3c9f27de592fcbc256dafe3af2717f56d7c87761fbaccf4" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "vte" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" +dependencies = [ + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote 1.0.35", +] + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "walkdir" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" +dependencies = [ + "kernel32-sys", + "same-file 0.1.3", + "winapi 0.2.8", +] + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file 1.0.6", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[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.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote 1.0.35", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "wasm-streams" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wayland-backend" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40" +dependencies = [ + "cc", + "downcast-rs", + "rustix 0.38.31", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" +dependencies = [ + "bitflags 2.4.0", + "rustix 0.38.31", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283" +dependencies = [ + "proc-macro2", + "quick-xml 0.31.0", + "quote 1.0.35", +] + +[[package]] +name = "wayland-sys" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webpki-roots" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" +dependencies = [ + "rustls-webpki 0.100.3", +] + +[[package]] +name = "webview2-com" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ae9c7e420783826cf769d2c06ac9ba462f450eca5893bb8c6c6529a4e5dd33" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows 0.52.0", + "windows-core", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "webview2-com-sys" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ad85fceee6c42fa3d61239eba5a11401bf38407a849ed5ea1b407df08cca72" +dependencies = [ + "thiserror", + "windows 0.52.0", + "windows-core", +] + +[[package]] +name = "whoami" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af6abc2b9c56bd95887825a1ce56cde49a2a97c07e28db465d541f5098a2656c" +dependencies = [ + "cocoa", + "objc", + "raw-window-handle 0.5.2", + "windows-sys 0.52.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-implement", + "windows-interface", + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-implement" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "windows-interface" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows-version" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75aa004c988e080ad34aff5739c39d0312f4684699d6d71fc8a198d057b8b9b4" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.5.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a1a57ff50e9b408431e8f97d5456f2807f8eb2a2cd79b06068fc87f8ecf189" +dependencies = [ + "cfg-if", + "winapi 0.3.9", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wry" +version = "0.35.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3016c47c9b6f7029a9da7cd48af8352327226bba0e955f3c92e2966651365a9" +dependencies = [ + "base64", + "block", + "cfg_aliases 0.1.1", + "cocoa", + "core-graphics", + "crossbeam-channel", + "dunce", + "gdkx11", + "gtk", + "html5ever", + "http", + "javascriptcore-rs", + "jni", + "kuchikiki", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc", + "objc_id", + "once_cell", + "raw-window-handle 0.5.2", + "serde", + "serde_json", + "sha2", + "soup3", + "tao-macros", + "thiserror", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows 0.52.0", + "windows-implement", + "windows-version", + "x11-dl", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading 0.8.1", + "once_cell", + "rustix 0.38.31", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34" + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys 0.4.13", + "rustix 0.38.31", +] + +[[package]] +name = "xdg" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" + +[[package]] +name = "xdg-home" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd" +dependencies = [ + "nix", + "winapi 0.3.9", +] + +[[package]] +name = "zbus" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31de390a2d872e4cd04edd71b425e29853f786dc99317ed72d73d6fcf5ebb948" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "byteorder", + "derivative", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix", + "once_cell", + "ordered-stream", + "rand 0.8.5", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi 0.3.9", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote 1.0.35", + "regex", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb80bb776dbda6e23d705cf0123c3b95df99c4ebeaec6c2599d4a5419902b4a9" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.49", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes 0.8.3", + "byteorder", + "bzip2", + "constant_time_eq 0.1.5", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "zvariant" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44b291bee0d960c53170780af148dca5fa260a63cdd24f1962fa82e03e53338c" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml new file mode 100644 index 00000000..c2e535d9 --- /dev/null +++ b/src-tauri/Cargo.toml @@ -0,0 +1,94 @@ +[package] +name = "avail_wallet" +version = "0.0.1" +description = "A Tauri App" +authors = ["Avail"] +license = "" +repository = "" +edition = "2021" + +[lib] +name = "availx_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[build-dependencies] +tauri-build = { version = "2.0.0-beta.1", features = [] } + + +[dependencies] +app_dirs = { package = "app_dirs2", version = "2.5" } +avail-common = { git = "https://github.com/availx/avail-lib", tag = "v0.5.0", features = [ + "snarkvm", +] } +bs58 = "0.5.0" +chrono = "0.4.26" +dirs = "5.0.1" +dotenv = "0.15.0" +fix-path-env = { git = "https://github.com/tauri-apps/fix-path-env-rs" } +futures = "0.3.28" +jni = { version = "0.21.1" } +keyring = "2.0.5" +libc = "0.2.147" +log = "0.4.19" +ndk-context = "0.1.1" +once_cell = "1.18.0" +openssl = { version = "0.10.36", features = ["vendored"] } +rand = "0.8.5" +rayon = "1.7.0" +rusqlite = { version = "0.29.0", features = ["bundled", "chrono"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +snarkvm = { version = "0.16.17", features = [] } +ssss = "0.2.0" +tauri = { version = "2.0.0-beta.1", features = [] } +tauri-plugin-deep-link = "2.0.0-beta" +tauri-plugin-http = { version = "2.0.0-beta", features = ["cookies"] } +tauri-plugin-updater = { version = "2.0.0-beta.0", features = [] } +tiny-bip39 = "1.0.0" +tokio = { version = "1.29.1", features = ["full"] } +ureq = { version = "2.7.1", features = ["json"] } +uuid = { version = "1.4.1", features = ["v4", "serde"] } +whoami = "1.4.1" +zeroize = { version = "1.7.0", features = [ + "aarch64", + "zeroize_derive", + "alloc", +] } + +[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] +keyring = "2.0.5" +security-framework = { git = "https://github.com/AvailX/rust-security-framework" } +security-framework-sys = { git = "https://github.com/AvailX/rust-security-framework" } +core-foundation = "0.9.3" +tid-rs = { git = "https://github.com/Zack-Xb/tid-rs" } + + +[profile.release] +opt-level = 3 +lto = "thin" +incremental = true + +[profile.bench] +opt-level = 3 +debug = false +rpath = false +lto = "thin" +incremental = true +debug-assertions = false + +[profile.dev] +opt-level = 2 +lto = "thin" +incremental = true + +[profile.test] + +[features] +# this feature is used for production builds or when `devPath` points to the filesystem +# DO NOT REMOVE!! +custom-protocol = ["tauri/custom-protocol"] + +[dev-dependencies] +rstest = "0.18.2" diff --git a/src-tauri/build.rs b/src-tauri/build.rs new file mode 100644 index 00000000..261851f6 --- /dev/null +++ b/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build(); +} diff --git a/src-tauri/capabilities/capabilities.toml b/src-tauri/capabilities/capabilities.toml new file mode 100644 index 00000000..a0564439 --- /dev/null +++ b/src-tauri/capabilities/capabilities.toml @@ -0,0 +1,20 @@ +"$schema" = "./schemas/desktop-schema.toml" +identifier = "main-capability" +description = "Capability for the main window" +windows = ["main", "walletConnect"] +permissions = [ + "path:default", + "event:default", + "event:allow-listen", + "window:default", + "window:allow-create", + "window:allow-close", + "window:allow-set-title", + "window:allow-destroy", + "webview:allow-create-webview-window", + "webview:default", + "app:default", + "resources:default", + "menu:default", + "tray:default", +] diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..8b5259350f3d7da2597e2443a4430dfd82525072 GIT binary patch literal 2837 zcmV+w3+nWVP)dihlk@@;HNt z56)HDMlh|yx*rW@GM1r+$)v>4`HBu@^Bjz#R5bIG6FCjgA|*Xr(Kggkj)+!_5`WKk42f%S{Tia^kzEw++9|FF zDBAs9s)_G&z%UYd;_F2GgN6rKZ~dQ>qri~i^#uxU-=X4%pKUO7S|EzrBM(w_d@og> z_@2{(5IKS|kt3ML>xKXd{GE%OqG@sn7`kxtQ|h~POS!?f0$!o|?>=5hJeCB)3) ze2qMd9wm!G3-7-m z4FA?GDFRzrJM@?%Lg1$(_KQ=o0MPnJ$UxNaEnsDaQEN%=^tqD z&!0H=(Q595V5D7;ppUIdxNdvE?K%K&jHpp1z7`(8CZ zz&r(>L56X`a3%tXjgJS=>%`9@D-jqMK-M4FMzVY+Mg@RA-y45(vJ!z&0eIuL2hV2c z**_W`4H**v5+T0N-x@rlf#1%NDU1jJsa@A|`X=cUGoGfNmv#Zbts%AR*&cO|slVPq zy8zJdd%9!j**|HI2eb+R=}sT?b&o89IeV3KqAeASo5$>z4WPoe`ou%^D&O6x^4%$` zf0M*Ql~u&I7v&XLQgZgc_kN?T?ogWmFzc07%^v38D+eE=%J`_vx8wV6fcp)vEl~01 zXB1w_t|AG>hX{0_MF5!Y#Eh3|FsZWk%OBF(p&xW@^j5$_V5++RY&PB6^6S&ICPb|o zEdnrI_yEJB>l&sYZDaXu3v!?Z|%m?~UIXGrs(r;%~tvR}MZ- zroc1RQAncP1DI<4aPjxvoXLDq2D||>cP7%eSd9d+t3;^>(6Jsv~?Am=Xaz zfXePhnE)_W)``hh)-9$4sxlZCz9 zRetQwmPM;G`?UtBD!TzC0?_IHWs=9TB~_iU{MxkEt^mv9RbagUTv~IVM5d)R3b*j# zr=$WU0^r{sBpt|yXfVU4n$;suYx4rC8l4gWET5U8yI)<9nK`6KRkc{OewT@7C3S$f zOGO-@G!cYA?cVE$<)lTND^DW^*Y@7o3`|MuLPe2nku(A0#RkNUB696}`=gGFENV}F z-^sqe89W2Ndnd6wUy^E2w34=wXcIsZjE&{^c;@NGkg@OWTWtfG%D5G))|G(I(x;)y zSH--G5dkEL13O%C#ZCDBf)qotPpdtgi;Wp2y7m-wQUFO1B*kKoHv`Wg(wx})4;~{g zpdL{NY|(K6G?R=Q@`SEf#=22}r!@!!Rm1KsQ(C+L3=!>6pDgnpz#;e!J=xNIAU6V#6|*=0C36UP z-A$6D)$i0ZnY*a^qtSY5H%EeSS^!8Kh3}WNZy_%ijEW0u0DwFwLQHhY1*eYBS2!mC zQ%2wF9^w)>WHDVlH6+Fv0mKV4ZQDy2UIAC^71j>ARls7s0BkjUGqG2|rWmLPbj2fB zD*#sv-%PyUpDRblSSNtIoD_m?0aM+m3tT;6Z)sbmyM;G{);{>cZ0`0I!Y~rK2OXaa zwU}wJ!UN=`)wjat4KgzqK)gMw-$gVVG8F)f4&(c+e-8S0bq8_ zCwc5es{oMO$0^_*d(kQYOze2Rw-Th2NkbJ8ChmG$dD)%k^%S1rNQ7QmatzRA!^WLwmsJN}~5I$pd;b%LPb^#`aO?c2NC-m;d z-3{?QVfgD3>b8p)0g>*$&{pHe;ND#G1PTS9X7}n=U`%hb@ndk0l|$xE6HAM_6GJo} z7lVFw<;)bh!t%?L&a4_%vt7L6b8MP%<+PBP`tWp`TtJBcLX8O#thRM=m=&)UwjDJ` z#@yC-NVKcNE8s%RqO1$h0b0MyJ8Xj_;+spzFK<6{HUW@9OFT9-zEnvo}lc z0q%T7szIM=bF0}d@eZUm0s$;h8Z>x-JRBCafxHSpOA0uLd-K-p?9$3Y04$vc@Hh)2 z1_AIJ4;YGmbJ{Mm`$kR)dBQ~{XJrBVB z)*ZdaU-2I)fQb6ek*BAKs3vV*_W*2SNel_*$`K< z097`Li11zVcwvnNSOBz-n5v1(Zm5>atX=)?UjFg&G*!m(EW z$lCoT@higtRX^~az**|X7kQpmZ)h)ob;Mi&;)0{(af$Q7?Z3Fyn>wlq#Qz9WhvH?K zJhmfRdvvT5?9fUEf#`FaA=lrfDjXL8#Fd0UZA07--x3RKu9+|Z~{dihlk@@;HNt z56)HDMlh|yx*rW@GM1r+$)v>4`HBu@^Bjz#R5bIG6FCjgA|*Xr(Kggkj)+!_5`WKk42f%S{Tia^kzEw++9|FF zDBAs9s)_G&z%UYd;_F2GgN6rKZ~dQ>qri~i^#uxU-=X4%pKUO7S|EzrBM(w_d@og> z_@2{(5IKS|kt3ML>xKXd{GE%OqG@sn7`kxtQ|h~POS!?f0$!o|?>=5hJeCB)3) ze2qMd9wm!G3-7-m z4FA?GDFRzrJM@?%Lg1$(_KQ=o0MPnJ$UxNaEnsDaQEN%=^tqD z&!0H=(Q595V5D7;ppUIdxNdvE?K%K&jHpp1z7`(8CZ zz&r(>L56X`a3%tXjgJS=>%`9@D-jqMK-M4FMzVY+Mg@RA-y45(vJ!z&0eIuL2hV2c z**_W`4H**v5+T0N-x@rlf#1%NDU1jJsa@A|`X=cUGoGfNmv#Zbts%AR*&cO|slVPq zy8zJdd%9!j**|HI2eb+R=}sT?b&o89IeV3KqAeASo5$>z4WPoe`ou%^D&O6x^4%$` zf0M*Ql~u&I7v&XLQgZgc_kN?T?ogWmFzc07%^v38D+eE=%J`_vx8wV6fcp)vEl~01 zXB1w_t|AG>hX{0_MF5!Y#Eh3|FsZWk%OBF(p&xW@^j5$_V5++RY&PB6^6S&ICPb|o zEdnrI_yEJB>l&sYZDaXu3v!?Z|%m?~UIXGrs(r;%~tvR}MZ- zroc1RQAncP1DI<4aPjxvoXLDq2D||>cP7%eSd9d+t3;^>(6Jsv~?Am=Xaz zfXePhnE)_W)``hh)-9$4sxlZCz9 zRetQwmPM;G`?UtBD!TzC0?_IHWs=9TB~_iU{MxkEt^mv9RbagUTv~IVM5d)R3b*j# zr=$WU0^r{sBpt|yXfVU4n$;suYx4rC8l4gWET5U8yI)<9nK`6KRkc{OewT@7C3S$f zOGO-@G!cYA?cVE$<)lTND^DW^*Y@7o3`|MuLPe2nku(A0#RkNUB696}`=gGFENV}F z-^sqe89W2Ndnd6wUy^E2w34=wXcIsZjE&{^c;@NGkg@OWTWtfG%D5G))|G(I(x;)y zSH--G5dkEL13O%C#ZCDBf)qotPpdtgi;Wp2y7m-wQUFO1B*kKoHv`Wg(wx})4;~{g zpdL{NY|(K6G?R=Q@`SEf#=22}r!@!!Rm1KsQ(C+L3=!>6pDgnpz#;e!J=xNIAU6V#6|*=0C36UP z-A$6D)$i0ZnY*a^qtSY5H%EeSS^!8Kh3}WNZy_%ijEW0u0DwFwLQHhY1*eYBS2!mC zQ%2wF9^w)>WHDVlH6+Fv0mKV4ZQDy2UIAC^71j>ARls7s0BkjUGqG2|rWmLPbj2fB zD*#sv-%PyUpDRblSSNtIoD_m?0aM+m3tT;6Z)sbmyM;G{);{>cZ0`0I!Y~rK2OXaa zwU}wJ!UN=`)wjat4KgzqK)gMw-$gVVG8F)f4&(c+e-8S0bq8_ zCwc5es{oMO$0^_*d(kQYOze2Rw-Th2NkbJ8ChmG$dD)%k^%S1rNQ7QmatzRA!^WLwmsJN}~5I$pd;b%LPb^#`aO?c2NC-m;d z-3{?QVfgD3>b8p)0g>*$&{pHe;ND#G1PTS9X7}n=U`%hb@ndk0l|$xE6HAM_6GJo} z7lVFw<;)bh!t%?L&a4_%vt7L6b8MP%<+PBP`tWp`TtJBcLX8O#thRM=m=&)UwjDJ` z#@yC-NVKcNE8s%RqO1$h0b0MyJ8Xj_;+spzFK<6{HUW@9OFT9-zEnvo}lc z0q%T7szIM=bF0}d@eZUm0s$;h8Z>x-JRBCafxHSpOA0uLd-K-p?9$3Y04$vc@Hh)2 z1_AIJ4;YGmbJ{Mm`$kR)dBQ~{XJrBVB z)*ZdaU-2I)fQb6ek*BAKs3vV*_W*2SNel_*$`K< z097`Li11zVcwvnNSOBz-n5v1(Zm5>atX=)?UjFg&G*!m(EW z$lCoT@higtRX^~az**|X7kQpmZ)h)ob;Mi&;)0{(af$Q7?Z3Fyn>wlq#Qz9WhvH?K zJhmfRdvvT5?9fUEf#`FaA=lrfDjXL8#Fd0UZA07--x3RKu9+|Z~{eXu)D zds(i{K<*(k_!|*D@6lPBJNpPeS&{_2Ab%&uI@AfI36S5TV99S4EAZKn2+k#IZAC$x=i_)V|OmqxRSb>LWnRDV>42_nNc*3BmCtdDb&8hTs)7 zdjTmobZ`?ddBm9WB|npad1 z;0xs=DmB+zUjMz*?!`=8*Tj9$fb|vsCHyVG-bUw_!lTuF&RDe`Yiwe002ovPDHLk FV1f!EiNpW^ literal 0 HcmV?d00001 diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..9842e74308b41d7ffc5bfe3e3e0633e319c8e29d GIT binary patch literal 3890 zcmeHJF;62$82x5;4GVkNJGGltcN zDJUivLp&Ra2Bmeu4?xNvK>G{uKbX8(bA*PwTPYpamXxZPte>kHdyclOPfcWnVFto8MDtR{a#S| zkkcG09F)=gfhHgf$DT22oXtFI3Nm|~o;7r>r)wL67P>%TOt-OY8WX*@wWAl^1;p9G zjy`9z>1{z)htoU~c8{k_D=mbHgn>ln5XH0moE)H>GmzO4$LMW#u5PorRGrhpjtIbE zp()IaWpadl9ljGhGlxL)?u+-F>>~l%^ML?S>le}06g)BO*w)Okten%iOnjDBUV$=a)hMdPz z8AdFe7H|Y9&v}D}yh$H;`(E}A@zm4|9MXGqqB?Y{S~OG*I#=5?Qg!^*C{&E_K{QtO zWLPcag>Va-XOrI)kE$*N+>CxzEN~%r`&h9_333;rBgLXT?+x4U&UsVR1~0lA}|qD`DmA@X!B)Gc*^(qkLT7BHFkiq3Fg`Dhmq7p(`rVwWWd zIqYD0BsO{~6%9*5L`Y1K$RDEka$iv%DEACxAh+U^%b>Q&tHD2YMJ4DB5+&%J4T)X&y{8?xm*`-ahu$%N&~53Cp!bx% zJEaeW6@3eeZOuK7z>Q+!apZz=UNheT65o_C2cN&8#hoZnH&zJ>L$x8)JB5lTO6yq* z1Ifcs;zbX`6N!%&v5W8&vx^4N#Zb}(UiFJ}jCHJtF~sX0j-(OB0}tsUMADb`pi*AU z36Wh~tqgvaY!vQE9+b0?b2ZolWKXiSEDZ4aShB$~46qm+NfzW_fLzd*v@(lk^G(SPVQ}3%!@SKw(^IW7!v&417ry7$6ty0+Pj< ztof2vS8!03j-)q8toCFosH_MPATdB9cZlNZzNF_sWzQtNfB_^QRM%^(yu7|&m$VE6 zfW$HkkXs8R!oCh+fZQ4aO&kW0vQA`{!JkHgVlm+XYW{(#h(v3U`$O;l5rXhbx z_CPZ&;YilC(C8HUvh(l{N#|Pd4@kfQcV@urFJ)|zQRvb7%J-W@a~9n_#h=DE>XGMm z>@R)9O~>N+5$Jt-T>P)X@$b{0nE1|Jg?s%8)Pt|C-MGN{Lby`b@eW@^X1a}!4T=wT z{Oq)-|7j+8#+<61I& zH_>&W)Kb#>BJq7h32uz8zEG3iryRBfGw{zy4^S;mX zUe1|wY8dCqZ(W_ized(Ij7q~W8bzebxK4!q>PN=Pt(@dK3}YM-Eg5O|hkMdpiWTw?-}T6xckoDw7YiET|K-L)*mAc=BXD{K|LoJ8+^5tFBL@ zzS%*;B{^Yx>uYhmF^l|g?$$%`GwfWpKCS#CR-S{x*7!r;nP^(=z)of0Iyqsx{V_}N z%j;;}f=}9Sf7F6){cFcbXA~dC#Dnj%F*0Rh&8=y0ZYGlx$If6yn~j4%m<9E`ylDI2 z_a;`f+MuqsLw^|4FnsFXwL9t4qkefs23z(gO2&V1FrjobHlL;7GjDr7j$vVq3)l5< zmv+q(7u&OOjQ$=`wcw2*+tkg<*u&%VP_xvpUn)N1$Q-nFrF=Qi`c;cuZ0NPn|4|ID zO069IErO#bBdWby`ZjK}P(|(%Yp?HGzgYZ`E znpsZ?hdy-2q2eZXzEV6$@u;a~n5^G!eN1uz~G9J}+E|#uzd~@f5PY$f@{a==$^XUYd zud-3GKw>U6KpZcuYB-jTx2_hRUNF5%0`T=6xB@xLN?<%EgH--)4XUjjGw zSZKXFh1QM~Ha=uw%U~P>pGRdqn0QM#Kk(9j!`Ew?>tS5#QS;zCWlZ=mKNODZe$He2 zz83`FlP|U}S{}atX^aW6H~f={fzP7oel~&aqjBFp&3R!$?)+w`yy$&g@SCo5F!XKs zKECgZDDLb};_@48l~3lF?Zd){cEfNr|3g2TSh>!>|C3A0O=;P)3V+LKf77m{`u?%T z)S8yMs+5}B_IhdGV8*`pa2ypE_}2>U-Tp)})CcPB`XGh{)vl^%z1En!C6_vQax$j$ zXNm*+D1D;eAbIxYo@;|PIYx{^F{J(xIk#Nh?*9gp2kq4_b5vcw{B`aeqcM4=;dk}^ z7ZX_A6u=f;#-285n>vN?*-w6b@5j_065LbCVSafA7hmCE{pOU4Cu6#=#7EqaIdWYMGdahv*uFGX>99(l-8XZq1vFDR0M&w)+w$Accyz}%< zz~mi>ccFs#dW<&d56=eN<9MIoTI6|mfBAgLgpQ4fS~FlRUgq xs-DcF-}IN5#@qROu-GCO-UW|~oXh)n4`VKPf^8X-hGF*cUj+a24>2bN`yZJ*qYD54 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8b5259350f3d7da2597e2443a4430dfd82525072 GIT binary patch literal 2837 zcmV+w3+nWVP)dihlk@@;HNt z56)HDMlh|yx*rW@GM1r+$)v>4`HBu@^Bjz#R5bIG6FCjgA|*Xr(Kggkj)+!_5`WKk42f%S{Tia^kzEw++9|FF zDBAs9s)_G&z%UYd;_F2GgN6rKZ~dQ>qri~i^#uxU-=X4%pKUO7S|EzrBM(w_d@og> z_@2{(5IKS|kt3ML>xKXd{GE%OqG@sn7`kxtQ|h~POS!?f0$!o|?>=5hJeCB)3) ze2qMd9wm!G3-7-m z4FA?GDFRzrJM@?%Lg1$(_KQ=o0MPnJ$UxNaEnsDaQEN%=^tqD z&!0H=(Q595V5D7;ppUIdxNdvE?K%K&jHpp1z7`(8CZ zz&r(>L56X`a3%tXjgJS=>%`9@D-jqMK-M4FMzVY+Mg@RA-y45(vJ!z&0eIuL2hV2c z**_W`4H**v5+T0N-x@rlf#1%NDU1jJsa@A|`X=cUGoGfNmv#Zbts%AR*&cO|slVPq zy8zJdd%9!j**|HI2eb+R=}sT?b&o89IeV3KqAeASo5$>z4WPoe`ou%^D&O6x^4%$` zf0M*Ql~u&I7v&XLQgZgc_kN?T?ogWmFzc07%^v38D+eE=%J`_vx8wV6fcp)vEl~01 zXB1w_t|AG>hX{0_MF5!Y#Eh3|FsZWk%OBF(p&xW@^j5$_V5++RY&PB6^6S&ICPb|o zEdnrI_yEJB>l&sYZDaXu3v!?Z|%m?~UIXGrs(r;%~tvR}MZ- zroc1RQAncP1DI<4aPjxvoXLDq2D||>cP7%eSd9d+t3;^>(6Jsv~?Am=Xaz zfXePhnE)_W)``hh)-9$4sxlZCz9 zRetQwmPM;G`?UtBD!TzC0?_IHWs=9TB~_iU{MxkEt^mv9RbagUTv~IVM5d)R3b*j# zr=$WU0^r{sBpt|yXfVU4n$;suYx4rC8l4gWET5U8yI)<9nK`6KRkc{OewT@7C3S$f zOGO-@G!cYA?cVE$<)lTND^DW^*Y@7o3`|MuLPe2nku(A0#RkNUB696}`=gGFENV}F z-^sqe89W2Ndnd6wUy^E2w34=wXcIsZjE&{^c;@NGkg@OWTWtfG%D5G))|G(I(x;)y zSH--G5dkEL13O%C#ZCDBf)qotPpdtgi;Wp2y7m-wQUFO1B*kKoHv`Wg(wx})4;~{g zpdL{NY|(K6G?R=Q@`SEf#=22}r!@!!Rm1KsQ(C+L3=!>6pDgnpz#;e!J=xNIAU6V#6|*=0C36UP z-A$6D)$i0ZnY*a^qtSY5H%EeSS^!8Kh3}WNZy_%ijEW0u0DwFwLQHhY1*eYBS2!mC zQ%2wF9^w)>WHDVlH6+Fv0mKV4ZQDy2UIAC^71j>ARls7s0BkjUGqG2|rWmLPbj2fB zD*#sv-%PyUpDRblSSNtIoD_m?0aM+m3tT;6Z)sbmyM;G{);{>cZ0`0I!Y~rK2OXaa zwU}wJ!UN=`)wjat4KgzqK)gMw-$gVVG8F)f4&(c+e-8S0bq8_ zCwc5es{oMO$0^_*d(kQYOze2Rw-Th2NkbJ8ChmG$dD)%k^%S1rNQ7QmatzRA!^WLwmsJN}~5I$pd;b%LPb^#`aO?c2NC-m;d z-3{?QVfgD3>b8p)0g>*$&{pHe;ND#G1PTS9X7}n=U`%hb@ndk0l|$xE6HAM_6GJo} z7lVFw<;)bh!t%?L&a4_%vt7L6b8MP%<+PBP`tWp`TtJBcLX8O#thRM=m=&)UwjDJ` z#@yC-NVKcNE8s%RqO1$h0b0MyJ8Xj_;+spzFK<6{HUW@9OFT9-zEnvo}lc z0q%T7szIM=bF0}d@eZUm0s$;h8Z>x-JRBCafxHSpOA0uLd-K-p?9$3Y04$vc@Hh)2 z1_AIJ4;YGmbJ{Mm`$kR)dBQ~{XJrBVB z)*ZdaU-2I)fQb6ek*BAKs3vV*_W*2SNel_*$`K< z097`Li11zVcwvnNSOBz-n5v1(Zm5>atX=)?UjFg&G*!m(EW z$lCoT@higtRX^~az**|X7kQpmZ)h)ob;Mi&;)0{(af$Q7?Z3Fyn>wlq#Qz9WhvH?K zJhmfRdvvT5?9fUEf#`FaA=lrfDjXL8#Fd0UZA07--x3RKu9+|Z~{() -> AleoAPIClient { + let dev_node_ip = env!("DEV_NODE_IP"); + let api_client = AleoAPIClient::::local_testnet3("3030", &dev_node_ip); + + api_client +} + +pub fn setup_client() -> AvailResult> { + let node_api_obscura = env!("TESTNET_API_OBSCURA"); + + println!("Node API Obscura: {:?}", node_api_obscura); + + let base_url = format!( + "https://aleo-testnet3.obscura.build/v1/{}", + node_api_obscura + ); + + let api_client = AleoAPIClient::::new(&base_url, "testnet3")?; + + Ok(api_client) +} + +/* --Solve Network Generic Global State-- */ +#[derive(Debug, Clone)] +pub struct AleoClient { + pub client: AleoAPIClient, +} + +impl AleoClient { + pub fn new() -> AvailResult { + let node_api_obscura = env!("MAINNET_API_OBSCURA"); + + let base_url = format!("https://aleo-mainnet.obscura.build/v1/{}", node_api_obscura); + + Ok(Self { + client: AleoAPIClient::::new(&base_url, "mainnet")?, + }) + } + + pub fn devnet() -> AvailResult { + let node_api_obscura = env!("DEVNET_API_OBSCURA"); + + let base_url = format!("https://aleo-devnet.obscura.build/v1/{}", node_api_obscura); + + Ok(Self { + client: AleoAPIClient::::new(&base_url, "devnet")?, + }) + } + + pub fn testnet3() -> AvailResult { + let node_api_obscura = env!("TESTNET_API_OBSCURA"); + + let base_url = format!( + "https://aleo-testnet3.obscura.build/v1/{}", + node_api_obscura + ); + + Ok(Self { + client: AleoAPIClient::::new(&base_url, "testnet3")?, + }) + } + + pub fn switch_network(network: &str) -> AvailResult<()> { + // Based on the network string, decide which network to switch to + let new_client = match network { + "testnet3" => { + update_network(EventNetwork::AleoTestnet); + AleoClient::::testnet3()? + } + //"devnet" => AleoClient::::devnet()?, + //"mainnet" => AleoClient::::mainnet()?, + _ => { + return Err(AvailError::new( + avail_common::errors::AvailErrorType::Network, + "Invalid network".to_string(), + "Invalid network".to_string(), + )) + } + }; + + // Acquire a write lock and update the ALEO_CLIENT + let mut aleo_client = ALEO_CLIENT.write().unwrap(); + *aleo_client = new_client; + + Ok(()) + } + + pub fn local_dev() -> AvailResult { + let dev_node_ip = env!("DEV_NODE_IP"); + + Ok(Self { + client: AleoAPIClient::local_testnet3("3030", &dev_node_ip), + }) + } + + pub fn get_instance(&self) -> &AleoAPIClient { + &self.client + } +} + +pub static ALEO_CLIENT: Lazy>> = + Lazy::new(|| RwLock::new(AleoClient::::testnet3().unwrap())); + +#[test] +fn test_new_client() { + let api_client = setup_client::().unwrap(); + let height = api_client.latest_height().unwrap(); + + println!("Height: {:?}", height); +} diff --git a/src-tauri/src/api/client.rs b/src-tauri/src/api/client.rs new file mode 100644 index 00000000..6699837c --- /dev/null +++ b/src-tauri/src/api/client.rs @@ -0,0 +1,100 @@ +use std::sync::{Arc, RwLock}; + +use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; +use once_cell::sync::Lazy; + +use crate::helpers::utils::HOST; +use tauri_plugin_http::reqwest; + +pub fn get_rm_client_with_session( + method: reqwest::Method, + path: &str, +) -> AvailResult { + let api = env!("API"); + + let client = reqwest::Client::new(); + let cookie_name = "id"; + + let session = match SESSION.get_session_token() { + Some(session) => session, + None => { + return Err(AvailError::new( + AvailErrorType::Validation, + "Session not found".to_string(), + "Session not found".to_string(), + )) + } + }; + + let cookie_value = format!("{}={}", cookie_name, session); + let url = format!("{}/encrypted_data/{}", api, path); + + let request = client + .request(method, url) + .header(reqwest::header::COOKIE, cookie_value); + Ok(request) +} + +pub fn get_um_client_with_session( + method: reqwest::Method, + path: &str, +) -> AvailResult { + let api = env!("API"); + + let client = reqwest::Client::new(); + let cookie_name = "id"; + + let session = match SESSION.get_session_token() { + Some(session) => session, + None => { + return Err(AvailError::new( + AvailErrorType::Validation, + "Session not found".to_string(), + "Session not found".to_string(), + )) + } + }; + + let cookie_value = format!("{}={}", cookie_name, session); + + let url = format!("{}/{}", api, path); + let request = client + .request(method, url) + .header(reqwest::header::COOKIE, cookie_value); + + Ok(request) +} + +// create a global state of a session string called SESSION + +#[derive(Debug)] +pub struct Session { + pub session: RwLock>, +} + +impl Session { + pub fn new() -> Self { + Self { + session: RwLock::new(None), + } + } + + pub fn set_session_token(&self, token: String) { + let mut token_write = self.session.write().unwrap(); + *token_write = Some(token); + } + + pub fn get_session_token(&self) -> Option { + let token_read = self.session.read().unwrap(); + token_read.clone() + } +} + +pub static SESSION: Lazy> = Lazy::new(|| Arc::new(Session::new())); + +#[test] +fn test_session() { + SESSION.set_session_token("test".to_string()); + let token = SESSION.get_session_token(); + assert_eq!(token, Some("test".to_string())); +} diff --git a/src-tauri/src/api/encrypted_data.rs b/src-tauri/src/api/encrypted_data.rs new file mode 100644 index 00000000..4b483e4c --- /dev/null +++ b/src-tauri/src/api/encrypted_data.rs @@ -0,0 +1,704 @@ +use snarkvm::{console::program::Itertools, prelude::Network}; +use std::str::FromStr; +use tauri_plugin_http::reqwest; +use uuid::Uuid; + +use crate::{ + api::client::get_rm_client_with_session, + models::pointers::message::TransactionMessage, + services::local_storage::{ + persistent_storage::{get_address_string, get_last_tx_sync, update_last_tx_sync}, + session::view::VIEWSESSION, + }, +}; + +use avail_common::{ + errors::{AvError, AvailError, AvailErrorType, AvailResult}, + models::{ + encrypted_data::{ + Data, DataRequest, EncryptedData, EncryptedDataRecord, EncryptedDataSyncRequest, + EncryptedDataUpdateRequest, PageRequest, + }, + traits::encryptable::EncryptedStruct, + }, +}; + +/* --ENCRYPTED DATA SERVICE-- */ + +/// update encrypted data by id +pub async fn update_data(data: Vec, idx: Vec) -> AvailResult { + const MAX_BATCH_SIZE: usize = 300; + + // Assuming data and idx have the same length + let batches = data.chunks(MAX_BATCH_SIZE); + let idx_batches = idx.chunks(MAX_BATCH_SIZE); + + for (batch, idx_batch) in batches.zip(idx_batches) { + let request = batch + .iter() + .enumerate() + .map(|(i, data)| { + let id = Uuid::from_str(&idx_batch[i])?; + Ok(EncryptedDataUpdateRequest { + id, + ciphertext: data.ciphertext.clone(), + nonce: data.nonce.clone(), + }) + }) + .collect::, AvailError>>()?; + + let res = get_rm_client_with_session(reqwest::Method::PUT, "data")? + .json(&request) + .send() + .await?; + + if res.status() == 200 { + let _result = res.text().await?; + } else if res.status() == 401 { + return Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )); + } else { + return Err(AvailError::new( + AvailErrorType::External, + "Error updating encrypted data record ".to_string(), + "Error updating backup data.".to_string(), + )); + } + } + + Ok("Updated Succesfully".to_string()) +} + +/// update transactions received to synced +pub async fn synced(ids: Vec) -> AvailResult { + let res = get_rm_client_with_session(reqwest::Method::PUT, "sync")? + .json(&ids) + .send() + .await?; + + if res.status() == 200 { + let result = res.text().await?; + Ok(result) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error syncing data".to_string(), + "Error syncing data".to_string(), + )) + } +} + +///recover_txs get all blocks, tx_in and tx_out back locally +pub async fn get_new_transaction_messages( +) -> AvailResult<(Vec>, Vec)> { + let address = get_address_string()?; + let last_sync_time = get_last_tx_sync()?; + + let request = EncryptedDataSyncRequest { + owner: address, + last_sync: last_sync_time, + }; + + let res = get_rm_client_with_session(reqwest::Method::POST, "txs_received")? + .json(&request) + .send() + .await?; + + if res.status() == 200 { + // update last sync time + update_last_tx_sync(chrono::Utc::now())?; + + let result: Vec = res.json().await?; + + println!("Enc Data {:?}", result); + let encrypted_txs = result + .clone() + .into_iter() + .map(|x| x.to_enrypted_struct::()) + .collect::>>>()?; + + let v_key = VIEWSESSION.get_instance::()?; + + let txs_in: Vec> = encrypted_txs + .into_iter() + .map(|x| x.decrypt(v_key)) + .collect::>, _>>()?; + + let ids = result + .into_iter() + .map(|x| { + x.id.ok_or_else(|| { + AvailError::new( + AvailErrorType::Internal, + "Transaction id not found".to_string(), + "Transaction Id not found".to_string(), + ) + }) + }) + .collect::, AvailError>>()?; + + Ok((txs_in, ids)) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error checking transaction messages".to_string(), + "Error checking transaction messages".to_string(), + )) + } +} + +pub async fn post_encrypted_data(request: Vec) -> AvailResult> { + const MAX_BATCH_SIZE: usize = 300; + let mut ids: Vec = Vec::new(); + + // Split the request into batches of MAX_BATCH_SIZE + let batches = request.chunks(MAX_BATCH_SIZE); + + for batch in batches { + let request = batch + .into_iter() + .map(|data| EncryptedDataRecord::from(data.to_owned())) + .collect::>(); + + let res = get_rm_client_with_session(reqwest::Method::POST, "data")? + .json(&request) + .send() + .await?; + + if res.status() == 200 { + let result = res.text().await?; + let batch_ids: Vec = serde_json::from_str(&result)?; + ids.extend(batch_ids); + } else if res.status() == 401 { + return Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )); + } else { + return Err(AvailError::new( + AvailErrorType::External, + "Error posting encrypted data ".to_string(), + "".to_string(), + )); + } + } + + Ok(ids) +} + +pub async fn send_transaction_in(request: EncryptedData) -> AvailResult { + let res = get_rm_client_with_session(reqwest::Method::POST, "tx_sent")? + .json(&EncryptedDataRecord::from(request)) + .send() + .await?; + + if res.status() == 200 { + let result = res.text().await?; + + Ok(result) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error posting encrypted data ".to_string(), + "".to_string(), + )) + } +} + +pub async fn delete_invalid_transactions_in(ids: Vec) -> AvailResult { + let res = get_rm_client_with_session(reqwest::Method::DELETE, "txs_in")? + .json(&ids) + .send() + .await?; + + if res.status() == 200 { + let result = res.text().await?; + + Ok(result) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error deleting invalid transaction messages".to_string(), + "Error deleting invalid transaction messages".to_string(), + )) + } +} + +pub async fn get_data_count() -> AvailResult { + let res = get_rm_client_with_session(reqwest::Method::GET, "data_count")? + .send() + .await?; + + if res.status() == 200 { + let result = res.text().await?; + let count = result.parse::()?; + Ok(count) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error getting encrypted data count".to_string(), + "Error getting encrypted data count".to_string(), + )) + } +} + +pub async fn recover_data(_address: &str) -> AvailResult { + let data_count = get_data_count().await?; + let pages = (data_count as f64 / 300.0).ceil() as i64; + + let mut encrypted_data: Vec = vec![]; + + for page in 0..pages { + let page_request = PageRequest { page }; + + let res = get_rm_client_with_session(reqwest::Method::GET, "recover_data")? + .json(&page_request) + .send() + .await?; + + if res.status() == 200 { + let result: Data = res.json().await?; + encrypted_data.push(result); + } else if res.status() == 401 { + return Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )); + } else { + return Err(AvailError::new( + AvailErrorType::External, + "Error recovering encrypted data ".to_string(), + "Error recovering encrypted data".to_string(), + )); + } + } + + let mut record_pointers: Vec = vec![]; + let mut transactions: Vec = vec![]; + let mut transitions: Vec = vec![]; + let mut deployments: Vec = vec![]; + + for data in encrypted_data { + record_pointers.extend(data.record_pointers); + transactions.extend(data.transactions); + transitions.extend(data.transitions); + deployments.extend(data.deployments); + } + + Ok(Data { + record_pointers, + transactions, + transitions, + deployments, + }) +} + +pub async fn delete_all_server_storage() -> AvailResult { + let res = get_rm_client_with_session(reqwest::Method::DELETE, "data")? + .send() + .await?; + + if res.status() == 200 { + let result = res.text().await?; + + Ok(result) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error deleting encrypted data records ".to_string(), + "Error deleting server side data.".to_string(), + )) + } +} + +pub async fn import_encrypted_data(request: DataRequest) -> AvailResult { + // check that every vector in data request does not exceed 75 + + let record_pointers = request.data.record_pointers.len(); + let transactions = request.data.transactions.len(); + let transitions = request.data.transitions.len(); + let deployments = request.data.deployments.len(); + + // if they exceed 300 in sum, then split into several DataRequest where the sum of the data vectors inside is less than 300 + if record_pointers + transactions + transitions + deployments > 300 { + let mut data_requests: Vec = vec![]; + + let mut record_pointers = request.data.record_pointers.clone(); + let mut transactions = request.data.transactions.clone(); + let mut transitions = request.data.transitions.clone(); + let mut deployments = request.data.deployments.clone(); + + while record_pointers.len() + transactions.len() + transitions.len() + deployments.len() + > 300 + { + let mut record_pointers_batch = record_pointers.split_off(75); + let mut transactions_batch = transactions.split_off(75); + let mut transitions_batch = transitions.split_off(75); + let mut deployments_batch = deployments.split_off(75); + + let data: Data = Data { + record_pointers: record_pointers.clone(), + transactions: transactions.clone(), + transitions: transitions.clone(), + deployments: deployments.clone(), + }; + + let data_request = DataRequest { + address: request.address.clone(), + data, + }; + + data_requests.push(data_request); + + record_pointers = record_pointers_batch; + transactions = transactions_batch; + transitions = transitions_batch; + deployments = deployments_batch; + } + + let data = Data { + record_pointers, + transactions, + transitions, + deployments, + }; + + let data_request = DataRequest { + address: request.address.clone(), + data, + }; + + data_requests.push(data_request); + + for data_request in data_requests { + let res = get_rm_client_with_session(reqwest::Method::POST, "import_data")? + .json(&data_request) + .send() + .await?; + + if res.status() != 200 { + return Err(AvailError::new( + AvailErrorType::External, + "Error importing encrypted data.".to_string(), + "Error backing up encrypted data.".to_string(), + )); + } + } + + Ok("Imported Succesfully".to_string()) + } else { + let res = get_rm_client_with_session(reqwest::Method::POST, "import_data")? + .json(&request) + .send() + .await?; + + if res.status() == 200 { + let result = res.text().await?; + Ok(result) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error importing encrypted data.".to_string(), + "Error backing up encrypted data.".to_string(), + )) + } + } +} + +#[cfg(test)] + +mod encrypted_data_api_tests { + use super::*; + use crate::api::encrypted_data::{delete_all_server_storage, post_encrypted_data}; + + use crate::services::local_storage::encrypted_data::{ + delete_user_encrypted_data, get_encrypted_data_by_flavour, initialize_encrypted_data_table, + }; + use crate::services::local_storage::persistent_storage::{ + delete_user_preferences, get_address, initial_user_preferences, + }; + use crate::services::local_storage::storage_api::records::{ + encrypt_and_store_records, get_test_record_pointer, + }; + + use crate::services::local_storage::session::view::VIEWSESSION; + + use crate::models::storage::languages::Languages; + + use avail_common::models::encrypted_data::EncryptedDataTypeCommon; + use snarkvm::prelude::{PrivateKey, Testnet3, ToBytes, ViewKey}; + + use avail_common::models::constants::*; + + //TODO - Update endpoints required to test transactions in + #[tokio::test] + async fn test_get_new_transaction_messages() { + let address = get_address_string().unwrap(); + println!("{}", address); + let result = get_new_transaction_messages::().await.unwrap(); + println!("{:?}", result); + } + + #[tokio::test] + async fn test_update_data() { + let encrypted_record = EncryptedData::new( + Some(Uuid::new_v4()), + "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px".to_string(), + "some ciphertext".to_string(), + "some nonce".to_string(), + EncryptedDataTypeCommon::Record, + None, + None, + None, + chrono::Utc::now(), + None, + None, + "testnet3".to_string(), + Some("record_name".to_string()), + Some(false), + None, + None, + None, + ); + + let updated_encrypted_record = EncryptedData::new( + Some(Uuid::new_v4()), + "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px".to_string(), + "some ciphertext".to_string(), + "some nonce".to_string(), + EncryptedDataTypeCommon::Record, + None, + None, + None, + chrono::Utc::now(), + None, + None, + "testnet3".to_string(), + Some("record_name".to_string()), + Some(false), + None, + None, + None, + ); + + let ids = post_encrypted_data(vec![encrypted_record]).await.unwrap(); + + let res = update_data(vec![updated_encrypted_record], ids) + .await + .unwrap(); + + println!("{:?}", res); + delete_all_server_storage().await.unwrap(); + } + + #[tokio::test] + async fn test_synced() { + let encrypted_record = EncryptedData::new( + Some(Uuid::new_v4()), + "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px".to_string(), + "some ciphertext".to_string(), + "some nonce".to_string(), + EncryptedDataTypeCommon::Record, + None, + None, + None, + chrono::Utc::now(), + None, + None, + "testnet3".to_string(), + Some("record_name".to_string()), + Some(false), + None, + None, + None, + ); + + post_encrypted_data(vec![encrypted_record.clone()]) + .await + .unwrap(); + let ids = vec![encrypted_record.id.unwrap()]; + + let result = synced(ids).await.unwrap(); + println!("{:?}", result); + delete_all_server_storage().await.unwrap(); + } + + #[tokio::test] + async fn test_post_encrypted_data() { + let encrypted_record = EncryptedData::new( + Some(Uuid::new_v4()), + "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px".to_string(), + "some ciphertext".to_string(), + "some nonce".to_string(), + EncryptedDataTypeCommon::Record, + None, + None, + None, + chrono::Utc::now(), + None, + None, + "testnet3".to_string(), + Some("record_name".to_string()), + Some(false), + None, + None, + None, + ); + + let res = post_encrypted_data(vec![encrypted_record]).await.unwrap(); + + println!("{:?}", res); + delete_all_server_storage().await.unwrap(); + } + + #[tokio::test] + async fn test_recover_data() { + let encrypted_record = EncryptedData::new( + Some(Uuid::new_v4()), + "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px".to_string(), + "some ciphertext".to_string(), + "some nonce".to_string(), + EncryptedDataTypeCommon::Record, + None, + None, + None, + chrono::Utc::now(), + None, + None, + "testnet3".to_string(), + Some("record_name".to_string()), + Some(false), + None, + None, + None, + ); + + let res = post_encrypted_data(vec![encrypted_record]).await.unwrap(); + + println!("{:?}", res); + let address = get_address_string().unwrap(); + + let result = recover_data(&address).await.unwrap(); + println!("{:?}", result); + delete_all_server_storage().await.unwrap(); + } + + #[tokio::test] + async fn test_delete_all() { + let result = delete_all_server_storage().await.unwrap(); + println!("{:?}", result); + } + + fn test_setup_prerequisites() { + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let view_key = ViewKey::::try_from(&pk).unwrap(); + + delete_user_encrypted_data().unwrap(); + + delete_user_preferences().unwrap(); + // initialize the user preferences + initial_user_preferences( + false, + None, + None, + false, + false, + view_key.to_address().to_string(), + Languages::English, + ) + .unwrap(); + initialize_encrypted_data_table().unwrap(); + + VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); + } + + #[tokio::test] + async fn test_import_encrypted_data() { + test_setup_prerequisites(); + let test_pointer = get_test_record_pointer(); + let address = get_address::().unwrap(); + + encrypt_and_store_records(vec![test_pointer], address).unwrap(); + + let encrypted_record_pointers = + get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record).unwrap(); + let backup_encrypted_records = encrypted_record_pointers + .iter() + .map(|encrypted_record| EncryptedDataRecord::from(encrypted_record.to_owned())) + .collect::>(); + + let encrypted_transactions = + get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transaction).unwrap(); + let backup_encrypted_transactions = encrypted_transactions + .iter() + .map(|encrypted_transaction| { + EncryptedDataRecord::from(encrypted_transaction.to_owned()) + }) + .collect::>(); + + let encrypted_deployments = + get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Deployment).unwrap(); + let backup_encrypted_deployments = encrypted_deployments + .iter() + .map(|encrypted_deployment| EncryptedDataRecord::from(encrypted_deployment.to_owned())) + .collect::>(); + + let encrypted_transitions = + get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transition).unwrap(); + let backup_encrypted_transitions = encrypted_transitions + .iter() + .map(|encrypted_transition| EncryptedDataRecord::from(encrypted_transition.to_owned())) + .collect::>(); + + let data = Data::new( + backup_encrypted_records, + backup_encrypted_transactions, + backup_encrypted_transitions, + backup_encrypted_deployments, + ); + + let address = get_address_string().unwrap(); + + let request = DataRequest { address, data }; + + let result = import_encrypted_data(request).await.unwrap(); + println!("{:?}", result); + + delete_all_server_storage().await.unwrap(); + } +} diff --git a/src-tauri/src/api/fee.rs b/src-tauri/src/api/fee.rs new file mode 100644 index 00000000..9756042a --- /dev/null +++ b/src-tauri/src/api/fee.rs @@ -0,0 +1,176 @@ +use tauri_plugin_http::reqwest; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::fee_request::FeeRequest, +}; + +/* + create_record(request) - A function to handle the API call to the Avail's Fee Estimation Microservice to add Fee Data to the database. + Inputs - A FeeRequest Struct with execution_object, program_id, function_id, network +*/ +pub async fn create_record(request: FeeRequest) -> AvailResult { + let client = reqwest::Client::new(); + + let res = client + .post(format!("http://localhost:8080/fee/create-record")) + .json(&request) + .send() + .await?; + + if res.status() == 200 { + let result = res.json().await?; + + Ok(result) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Fee record creation FAILED".to_string(), + "Fee estimation failed.".to_string(), + )) + } +} +/* + fetch_record(pid,fid) - A function to handle the API call to the Avail's Fee Estimation Microservice to fetch Fee Data from the database. + Inputs - program_id and function_id + Output - fee +*/ +pub async fn fetch_record(pid: String, fid: String) -> AvailResult> { + let client = reqwest::Client::new(); + + let res = client + .get(format!( + "http://localhost:8080/fee/fetch-record/{}/{}", + pid, fid + )) + .send() + .await?; + + if res.status() == 200 { + let result: Option = res.json().await?; + + Ok(result) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error getting fee.".to_string(), + "Error getting fee.".to_string(), + )) + } +} + +#[cfg(test)] + +mod tests { + use std::str::FromStr; + + use avail_common::aleo_tools::program_manager::ProgramManager; + use avail_common::models::{ + constants::{TESTNET3_ADDRESS, TESTNET3_PRIVATE_KEY}, + network::SupportedNetworks, + }; + use snarkvm::{ + circuit::AleoV0, + prelude::{Address, Execution, PrivateKey, Testnet3}, + }; + + use crate::api::aleo_client::{setup_client, setup_local_client}; + + use super::*; + + #[tokio::test] + async fn test_create_record() { + let new_exec = get_execution_object().await.unwrap(); + // let new_exec = Execution::::new(); + let exec_obj: Vec = FeeRequest::to_bytes_execution_object::(new_exec) + .await + .unwrap(); + // println!("{:?}", exec_obj); + let req: FeeRequest = FeeRequest::new( + exec_obj, + "testing.aleo".to_string(), + "testing_7".to_string(), + SupportedNetworks::Testnet3, + ); + println!("Sending req...."); + let result: String = create_record(req).await.unwrap(); + + println!("{:?}", result); + } + + #[tokio::test] + async fn test_fetch_fee_record() { + let result = fetch_record("testing.aleo".to_string(), "testing_6".to_string()) + .await + .unwrap(); + println!("{:?}", result); + } + + async fn get_execution_object() -> AvailResult> { + let pk = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); + let api_client = setup_client::().unwrap(); + let recipient = Address::::from_str(TESTNET3_ADDRESS).unwrap(); + + let program = api_client.get_program("credits.aleo").unwrap(); + + let program_manager = + ProgramManager::::new(Some(pk), None, Some(api_client), None).unwrap(); + + let (total, (_, _), execution) = program_manager + .estimate_execution_fee::( + &program, + "transfer_public_to_private", + vec![recipient.to_string(), "10000u64".to_string()].iter(), + ) + .unwrap(); + //println!("{:?} ... {:?}...{:?}",txn.id(),txn.fee_amount(),txn.base_fee_amount()); + //let exec_option = txn.execution(); + + println!("{:?}", total); + // let exec= exec_option.unwrap(); + //let ex = exec.clone(); + //println!("{:?}", ex.to_execution_id()); + //Ok(ex) + Ok(execution) + } + + #[tokio::test] + async fn test_get_execution_object() { + let pk = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); + let api_client = setup_client::().unwrap(); + let recipient = Address::::from_str(TESTNET3_ADDRESS).unwrap(); + + let program = api_client.get_program("credits.aleo").unwrap(); + + let program_manager = + ProgramManager::::new(Some(pk), None, Some(api_client), None).unwrap(); + + let (total, (_x, _y), _execution) = program_manager + .estimate_execution_fee::( + &program, + "transfer_public_to_private", + vec![recipient.to_string(), "10000u64".to_string()].iter(), + ) + .unwrap(); + //println!("{:?} ... {:?}...{:?}",txn.id(),txn.fee_amount(),txn.base_fee_amount()); + //let exec_option = txn.execution(); + + println!("{:?}", total); + // let exec= exec_option.unwrap(); + //let ex = exec.clone(); + //println!("{:?}", ex.to_execution_id()); + //Ok(ex) + } +} diff --git a/src-tauri/src/api/tokens.rs b/src-tauri/src/api/tokens.rs new file mode 100644 index 00000000..757cef3e --- /dev/null +++ b/src-tauri/src/api/tokens.rs @@ -0,0 +1,52 @@ +use tauri_plugin_http::reqwest; + +use crate::helpers::utils::HOST; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::tokens::Token, +}; +//TODO - Update for V2 + +/* --TOKENS-- */ + +/// Fetches list of tokens to be listed to user in ui, for example for swaps. +#[tokio::main(flavor = "current_thread")] +pub async fn get_token_list() -> AvailResult> { + let client = reqwest::Client::new(); + + let res = client + .get(format!("http://{}:8100/token", HOST)) + .send() + .await?; + + if res.status() == 200 { + let result: Vec = res.json().await?; + + Ok(result) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error getting token list.".to_string(), + "Error getting token list.".to_string(), + )) + } +} + +#[cfg(test)] + +mod tests { + use super::*; + + #[test] + fn test_get_token_list() { + let result = get_token_list().unwrap(); + println!("{:?}", result); + } +} diff --git a/src-tauri/src/api/user.rs b/src-tauri/src/api/user.rs new file mode 100644 index 00000000..4a124f28 --- /dev/null +++ b/src-tauri/src/api/user.rs @@ -0,0 +1,259 @@ +use snarkvm::prelude::*; +use std::str::FromStr; +use tauri_plugin_http::reqwest; + +use crate::api::client::get_um_client_with_session; +use crate::helpers::utils::HOST; +use crate::helpers::validation::validate_address; +use crate::models::account::AddressRequest; +use crate::services::local_storage::persistent_storage::{ + get_backup_flag, update_local_backup_flag, +}; +use crate::services::{ + account::utils::generate_discriminant, + local_storage::persistent_storage::{get_address_string, update_username_local}, +}; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::user::{UpdateBackupRequest, User}, +}; + +/* --USER SERVICE-- */ + +// create user online account +pub async fn create_user(request: User) -> AvailResult { + let api = env!("API"); + + let client = reqwest::Client::new(); + + let res = client + .post(format!("{}/user", api)) + .json(&request) + .send() + .await?; + + if res.status() == 200 { + Ok("User created".to_string()) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error creating user".to_string(), + "Error creating user".to_string(), + )) + } +} + +// get user online account +pub async fn get_user() -> AvailResult { + let res = get_um_client_with_session(reqwest::Method::GET, "user")? + .send() + .await?; + + if res.status() == 200 { + let user: User = res.json().await?; + + Ok(user) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error getting user".to_string(), + "Error getting user".to_string(), + )) + } +} + +/// delete user on server-side +pub async fn delete_user() -> AvailResult { + let res = get_um_client_with_session(reqwest::Method::DELETE, "user")? + .send() + .await?; + + if res.status() == 200 { + Ok("User deleted".to_string()) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else if res.status() == 404 { + Ok("User not found".to_string()) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error deleting user account on server side.".to_string(), + "Error deleting online account.".to_string(), + )) + } +} + +//get aleo address from username +pub async fn name_to_address(username: &str) -> AvailResult> { + let _validation = match validate_address(username) { + Ok(_) => return Ok(Address::::from_str(username)?), + Err(_) => false, + }; + + let request = AddressRequest { + username: username.to_string(), + }; + + let res = get_um_client_with_session(reqwest::Method::GET, &format!("user_address"))? + .json(&request) + .send() + .await?; + + if res.status() == 200 { + let address: String = res.json().await?; + + print!("{}", address); + + let address = Address::::from_str(&address).unwrap(); + + Ok(address) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error getting address".to_string(), + "Error getting address".to_string(), + )) + } +} + +pub async fn get_username(address: &str) -> AvailResult> { + let res = get_um_client_with_session(reqwest::Method::GET, &format!("username/{}", address))? + .send() + .await?; + + if res.status() == 200 { + let username: Option = res.json().await?; + + Ok(username) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error getting username".to_string(), + "Error getting username".to_string(), + )) + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn update_username(username: &str) -> AvailResult { + let address = get_address_string()?; + let backup = get_backup_flag()?; + + let tag = generate_discriminant(); + + let res = get_um_client_with_session(reqwest::Method::PUT, "user")? + .json(&User::new( + Some(username.to_string()), + address, + Some(tag as u32), + backup, + )) + .send() + .await?; + + if res.status() == 200 { + update_username_local(username, tag as i32)?; + Ok("Username updated".to_string()) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error updating username".to_string(), + "Error updating username".to_string(), + )) + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn update_backup_flag(backup_flag: bool) -> AvailResult<()> { + let request = UpdateBackupRequest { + backup: backup_flag, + }; + + // TODO - Handle backup flag being false and server side backup being true + // Should backup get deleted on server side? + + let res = get_um_client_with_session(reqwest::Method::PUT, "backup")? + .json(&request) + .send() + .await?; + + if res.status() == 200 { + update_local_backup_flag(backup_flag)?; + Ok(()) + } else if res.status() == 401 { + Err(AvailError::new( + AvailErrorType::Unauthorized, + "User session has expired.".to_string(), + "Your session has expired, please authenticate again.".to_string(), + )) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Error updating username".to_string(), + "Error updating username".to_string(), + )) + } +} + +#[cfg(test)] + +mod tests { + use super::*; + + #[tokio::test] + async fn test_create_user() { + let address = "aleo1ckcdjd9wned6s9eqprf2km88znlmh2je03jg2ctxat5k4hllzuqq47j3zg".to_string(); + let username = Some("AvailInhabitantX".to_string()); + let tag = 1234; + + let request = User::new(username, address, Some(tag as u32), false); + + // let result = block_on(create_user(request)).unwrap(); + + let result = create_user(request).await.unwrap(); + println!("{:?}", result); + } + + #[tokio::test] + async fn test_name_to_address() { + let username = "AvailInhabitantX"; + + let result = name_to_address::(username).await.unwrap(); + println!("{:?}", result); + } + + #[tokio::test] + async fn test_delete_user() { + let result = delete_user().await.unwrap(); + println!("{:?}", result); + } +} diff --git a/src-tauri/src/helpers.rs b/src-tauri/src/helpers.rs new file mode 100644 index 00000000..8acefa98 --- /dev/null +++ b/src-tauri/src/helpers.rs @@ -0,0 +1,3 @@ +pub mod upgrade; +pub mod utils; +pub mod validation; diff --git a/src-tauri/src/helpers/upgrade.rs b/src-tauri/src/helpers/upgrade.rs new file mode 100644 index 00000000..69caa5e0 --- /dev/null +++ b/src-tauri/src/helpers/upgrade.rs @@ -0,0 +1,58 @@ +/* THIS IS TO FACILITATE UPGRADING FROM A SEED PHRASE WALLET TO A NORMAL AVAIL WALLET */ + +use crate::{ + api::encrypted_data::import_encrypted_data, + services::local_storage::{encrypted_data::*, persistent_storage::get_address_string}, +}; +use avail_common::{ + errors::AvailResult, + models::encrypted_data::{Data, DataRequest, EncryptedDataRecord, EncryptedDataTypeCommon}, +}; + +pub async fn upgrade() -> AvailResult { + let encrypted_record_pointers = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record)?; + let backup_encrypted_records = encrypted_record_pointers + .iter() + .map(|encrypted_record| EncryptedDataRecord::from(encrypted_record.to_owned())) + .collect::>(); + + let encrypted_transactions = + get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transaction)?; + let backup_encrypted_transactions = encrypted_transactions + .iter() + .map(|encrypted_transaction| EncryptedDataRecord::from(encrypted_transaction.to_owned())) + .collect::>(); + + let encrypted_transitions = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transition)?; + let backup_encrypted_transitions = encrypted_transitions + .iter() + .map(|encrypted_transition| EncryptedDataRecord::from(encrypted_transition.to_owned())) + .collect::>(); + + let encrypted_deployments = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Deployment)?; + let backup_encrypted_deployments = encrypted_deployments + .iter() + .map(|encrypted_deployment| EncryptedDataRecord::from(encrypted_deployment.to_owned())) + .collect::>(); + + let data = Data::new( + backup_encrypted_records, + backup_encrypted_transactions, + backup_encrypted_transitions, + backup_encrypted_deployments, + ); + + let address = get_address_string()?; + + let request = DataRequest { address, data }; + + let res = import_encrypted_data(request).await?; + + Ok(res) +} + +#[tokio::test] +async fn test_upgrade() { + let res = upgrade().await.unwrap(); + println!("{:?}", res); +} diff --git a/src-tauri/src/helpers/utils.rs b/src-tauri/src/helpers/utils.rs new file mode 100644 index 00000000..136303cb --- /dev/null +++ b/src-tauri/src/helpers/utils.rs @@ -0,0 +1,67 @@ +use super::validation; +use chrono::{DateTime, Local, NaiveDateTime, Utc}; +use snarkvm::prelude::{Ciphertext, Network, PrivateKey}; + +use avail_common::{ + aleo_tools::encryptor::Encryptor, + errors::{AvailError, AvailErrorType, AvailResult}, +}; + +/// This should be moved to utils and will most likely be deprecated. +/// Deprication depends on android local storage. +pub fn encrypt_key(key: PrivateKey, secret: &str) -> AvailResult> { + validation::validate_private_key(&key.to_string())?; + validation::validate_secret_password(secret)?; + + let encrypted_private_key = Encryptor::::encrypt_private_key_with_secret(&key, secret)?; + + Ok(encrypted_private_key) +} + +///This should be moved to utils and will most likely be deprecated. +/// Deprication depends on android local storage. +pub fn decrypt_key( + ciphertext: &Ciphertext, + secret: &str, +) -> AvailResult> { + let decrypted_private_key = + Encryptor::::decrypt_private_key_with_secret(ciphertext, secret)?; + + Ok(decrypted_private_key) +} + +pub fn get_timestamp_from_i64(i: i64) -> AvailResult> { + let naive_time = match NaiveDateTime::from_timestamp_opt(i, 0) { + Some(naive_time) => naive_time, + None => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Invalid block timestamp".to_string(), + "Invalid block timestamp".to_string(), + )) + } + }; + + let timestamp_datetime: DateTime = + DateTime::::from_naive_utc_and_offset(naive_time, Local::now().offset().to_owned()); + Ok(timestamp_datetime) +} + +pub fn get_timestamp_from_i64_utc(i: i64) -> AvailResult> { + let naive_time = match NaiveDateTime::from_timestamp_opt(i, 0) { + Some(naive_time) => naive_time, + None => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Invalid block timestamp".to_string(), + "Invalid block timestamp".to_string(), + )) + } + }; + + let utc_timestamp = DateTime::::from_utc(naive_time, Utc); + + Ok(utc_timestamp) +} + +pub const HOST: &str = "localhost"; diff --git a/src-tauri/src/helpers/validation.rs b/src-tauri/src/helpers/validation.rs new file mode 100644 index 00000000..54e7649f --- /dev/null +++ b/src-tauri/src/helpers/validation.rs @@ -0,0 +1,145 @@ +use bs58; +use snarkvm::prelude::bech32; + +use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; + +/// Validates an aleo private key checking it's length and prefix. +pub fn validate_private_key(pk: &String) -> AvailResult<()> { + if pk.len() != 59 { + return Err(AvailError::new( + AvailErrorType::InvalidData, + format!("Invalid private key with length {} != 59", pk.len()), + "Invalid private key".to_string(), + )); + } + + if &pk[0..12] != "APrivateKey1" { + return Err(AvailError::new( + AvailErrorType::InvalidData, + format!("Invalid private key starting with {}", &pk[0..12]), + "Invalid private key".to_string(), + )); + } + + let base58 = &pk[12..59]; + let _base58_res = bs58::decode(base58).into_vec()?; + + Ok(()) +} + +pub fn validate_address(address: &str) -> AvailResult { + if address.len() != 63 { + return Err(AvailError::new( + AvailErrorType::InvalidData, + format!("Invalid address with length {} != 63", address.len()), + "Invalid address".to_string(), + )); + } + + if &address[0..5] != "aleo1" { + return Err(AvailError::new( + AvailErrorType::InvalidData, + format!("Invalid address starting with {}", &address[0..5]), + "Invalid address".to_string(), + )); + } + + let _bech32_res = bech32::decode(address)?; + + Ok(true) +} + +pub fn validate_address_bool(address: &str) -> bool { + if address.len() != 63 { + return false; + } + + if &address[0..5] != "aleo1" { + return false; + } + + let _bech32_res = bech32::decode(address); + + match _bech32_res { + Ok(_) => true, + Err(_) => false, + } +} + +pub fn validate_secret_password(secret: &str) -> AvailResult<()> { + if secret.len() < 12 { + return Err(AvailError::new( + AvailErrorType::Validation, + format!("Invalid secret with length {} < 12", secret.len()), + "Invalid secret".to_string(), + )); + } + + let mut has_num = false; + let mut has_cap = false; + let mut has_special = false; + + for c in secret.chars() { + if c.is_numeric() { + has_num = true; + } else if c.is_uppercase() { + has_cap = true; + } else if c.is_ascii_punctuation() { + has_special = true; + } + } + + if !has_num || !has_cap || !has_special { + return Err(AvailError::new( + AvailErrorType::Validation, + "Password too weak, must include at least one number, one uppercase character and one symbol.".to_string(), + "Password too weak, must include at least one number, one uppercase character and one symbol.".to_string(), + )); + } + + // TODO: Entropy check + Ok(()) +} + +#[test] +fn test_validate_private_key() { + let pk_str = "APrivateKey1zkp4X9ApjTb7Rv8EABfZRugXBhbPzCL245GyNtYJP5GYY2k"; + + let _res = validate_private_key(&pk_str.to_string()).unwrap(); +} + +#[test] +fn test_validate_private_key_invalid() { + let pk_str = "APrivateKey1zkp4THISISNOTAPRIVATEKEYPzCL245GyNtYJP5GYY2k22"; + + let _res = validate_private_key(&pk_str.to_string()).unwrap_err(); +} + +#[test] +fn test_validate_address() { + let add_str = "aleo1dg722m22fzpz6xjdrvl9tzu5t68zmypj5p74khlqcac0gvednygqxaax0j"; + + let _res = validate_address(&add_str.to_string()).unwrap(); +} + +#[test] +fn test_validate_address_invalid() { + let add_str = "aleo2dg722m22fzpz6xjdrvl9tzu5t68zmypj5p74khlqcac0gvednygqxaax0"; + + let _res = validate_address(&add_str.to_string()).unwrap_err(); +} + +#[test] +fn test_validate_secret_password_safe() { + //entropy should invalidate this in the future + let password = "Password123!"; + + let _res = validate_secret_password(&password.to_string()).unwrap(); +} + +#[test] +fn test_validate_secret_password_unsafe() { + let password = "password"; + + let _res = validate_secret_password(&password.to_string()).unwrap_err(); +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs new file mode 100644 index 00000000..26878211 --- /dev/null +++ b/src-tauri/src/lib.rs @@ -0,0 +1,102 @@ +pub mod api; +pub mod helpers; +pub mod models; +pub mod services; + +use services::account::generation::create_seed_phrase_wallet; +use services::account::generation::import_wallet; +use services::account::phrase_recovery::recover_wallet_from_seed_phrase; +use services::account::utils::{open_url, os_type}; +use services::authentication::session::get_session; +use services::local_storage::persistent_storage::{ + get_address_string, get_auth_type, get_backup_flag, get_language, get_last_sync, get_network, + get_username, update_language, +}; + +use api::user::{update_backup_flag, update_username}; +use services::local_storage::{ + encrypted_data::get_and_store_all_data, + tokens::get_stored_tokens, + utils::{ + delete_local_for_recovery, delete_util, get_private_key_tauri, get_seed_phrase, + get_view_key_tauri, + }, +}; + +// record handliong services +// use crate::services::record_handling::utils::get_all_nft_data; +use services::record_handling::{ + sync::{blocks_sync, sync_backup, txs_sync}, + transfer::{pre_install_inclusion_prover, transfer}, +}; +// wallet connect services +use crate::services::wallet_connect_api::{ + decrypt_records, get_avail_event, get_avail_events, get_balance, get_event, get_events, + get_records, get_succinct_avail_event, get_succinct_avail_events, request_create_event, sign, + verify, +}; + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_deep_link::init()) + .setup(|app| { + #[cfg(desktop)] + app.handle() + .plugin(tauri_plugin_updater::Builder::new().build())?; + // NOTE: Updater is only supported on desktop platforms + + Ok(()) + }) + .invoke_handler(tauri::generate_handler![ + /* Account Management */ + create_seed_phrase_wallet, + recover_wallet_from_seed_phrase, + update_username, + import_wallet, + get_username, + delete_util, + delete_local_for_recovery, + get_private_key_tauri, + get_view_key_tauri, + get_seed_phrase, + get_and_store_all_data, + get_address_string, + get_last_sync, + get_backup_flag, + update_backup_flag, + get_network, + get_language, + update_language, + get_stored_tokens, + open_url, + os_type, + /* Authentication */ + get_session, + get_auth_type, + /* Scanning */ + txs_sync, + blocks_sync, + sync_backup, + /* Avail Services */ + get_avail_event, + get_avail_events, + // get_all_nft_data, + transfer, + /* --Wallet Connect Api */ + get_event, + get_events, + get_records, + request_create_event, + sign, + decrypt_records, + get_balance, + get_succinct_avail_event, + get_succinct_avail_events, + verify, + /* Aleo Helpers */ + pre_install_inclusion_prover + ]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs new file mode 100644 index 00000000..7f6f39eb --- /dev/null +++ b/src-tauri/src/main.rs @@ -0,0 +1,13 @@ +// Prevents additional console window on Windows in release, DO NOT REMOVE!! + +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +mod api; +mod helpers; +mod models; +mod services; + +fn main() { + #[cfg(desktop)] + availx_lib::run(); +} diff --git a/src-tauri/src/models.rs b/src-tauri/src/models.rs new file mode 100644 index 00000000..7737587f --- /dev/null +++ b/src-tauri/src/models.rs @@ -0,0 +1,9 @@ +pub mod account; +pub mod auth; +pub mod event; +pub mod event_payloads; +pub mod pointers; +pub mod storage; +pub mod transfer; +pub mod wallet; +pub mod wallet_connect; diff --git a/src-tauri/src/models/account.rs b/src-tauri/src/models/account.rs new file mode 100644 index 00000000..7ceb81f0 --- /dev/null +++ b/src-tauri/src/models/account.rs @@ -0,0 +1,24 @@ +use serde::{ser::SerializeStruct, Deserialize, Serialize}; +use snarkvm::prelude::{Address, Network, Testnet3, ViewKey}; + +pub struct AvailKeys { + pub view_key: ViewKey, + pub address: Address, +} + +impl Serialize for AvailKeys { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_struct("AvailKeys", 2)?; + state.serialize_field("view_key", &self.view_key.to_string())?; + state.serialize_field("address", &self.address.to_string())?; + state.end() + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct AddressRequest { + pub username: String, +} diff --git a/src-tauri/src/models/auth.rs b/src-tauri/src/models/auth.rs new file mode 100644 index 00000000..8f86abe7 --- /dev/null +++ b/src-tauri/src/models/auth.rs @@ -0,0 +1,134 @@ +#![allow(dead_code)] +use chrono::{DateTime, Utc}; +use openssl::base64; +use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer}; + +use avail_common::models::server_auth::{CreateSessionResponse, VerifySessionRequest}; +use uuid::Uuid; + +#[allow(non_snake_case)] +pub struct Options { + pub service: String, + pub title: String, + pub subtitle: String, + pub description: String, + pub cancel: String, + pub accessible: String, + pub accessControl: Option, + pub storage: Option, + pub securityLevel: String, + pub authenticationType: Option, +} +#[allow(non_snake_case)] +impl Options { + pub fn new( + service: String, + title: String, + subtitle: String, + description: String, + cancel: String, + accessible: String, + accessControl: Option, + storage: Option, + securityLevel: String, + authenticationType: Option, + ) -> Options { + Options { + service, + title, + subtitle, + description, + cancel, + accessible, + accessControl, + storage, + securityLevel, + authenticationType, + } + } + + pub fn default() -> Options { + Options { + service: String::from("com.avail"), + title: String::from("Authentication"), + subtitle: String::from("Login to your wallet"), + cancel: String::from("Cancel"), + description: String::from(""), + accessible: String::from("AccessibleWhenUnlockedThisDeviceOnly"), + accessControl: None, + storage: None, + securityLevel: String::from("ANY"), + authenticationType: None, + } + } +} + +pub struct PbkdfResult { + pub salt: [u8; 16], + pub hash: String, +} + +impl Serialize for PbkdfResult { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let salt = base64::encode_block(&self.salt); + let hash = &self.hash; + let mut state = serializer.serialize_struct("PbkdfResult", 2)?; + state.serialize_field("salt", &salt)?; + state.serialize_field("hash", &hash)?; + state.end() + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct VerifySessionResponse { + pub signature: String, + pub session_id: String, +} + +impl VerifySessionResponse { + pub fn to_request(&self) -> VerifySessionRequest { + VerifySessionRequest { + signature: self.signature.to_string(), + session_id: Uuid::parse_str(&self.session_id).unwrap(), + } + } +} + +impl From for VerifySessionResponse { + fn from(request: VerifySessionRequest) -> Self { + VerifySessionResponse { + signature: request.signature, + session_id: request.session_id.to_string(), + } + } +} + +#[derive(Serialize, Deserialize)] +pub struct CreateSessionRequest { + pub hash: String, + pub session_id: String, + pub expires_on: DateTime, +} + +impl CreateSessionRequest { + pub fn to_response(&self) -> CreateSessionResponse { + CreateSessionResponse { + hash: self.hash.to_string(), + session_id: Uuid::parse_str(&self.session_id).unwrap(), + expires_on: self.expires_on, + } + } +} + +impl From for CreateSessionRequest { + fn from(response: CreateSessionResponse) -> Self { + CreateSessionRequest { + hash: response.hash, + session_id: response.session_id.to_string(), + expires_on: response.expires_on, + } + } +} diff --git a/src-tauri/src/models/event.rs b/src-tauri/src/models/event.rs new file mode 100644 index 00000000..dd74d40d --- /dev/null +++ b/src-tauri/src/models/event.rs @@ -0,0 +1,346 @@ +use avail_common::models::encrypted_data::{EventStatus, EventTypeCommon, TransactionState}; +use chrono::{DateTime, Local}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +pub struct Event { + _id: String, + #[serde(rename = "type")] + event_type: EventTypeCommon, + owner: String, + status: EventStatus, + created: DateTime, + broadcast: Option>, // finalized + #[serde(rename = "broadcastHeight")] + broadcast_height: Option, // finalized height + settled: Option>, // i.e confirmed + network: Network, + #[serde(rename = "transactionId")] + transaction_id: Option, + #[serde(rename = "programId")] + program_id: Option, + #[serde(rename = "functionId")] + function_id: Option, + inputs: Vec, + transitions: Vec, + fee_transition: Option, + height: Option, + description: Option, + fee: Option, + visibility: Visibility, // public or private + error: Option, +} + +impl Event { + pub fn new( + _id: String, + event_type: EventTypeCommon, + owner: String, + status: EventStatus, + created: DateTime, + broadcast: Option>, + broadcast_height: Option, + settled: Option>, + network: Network, + transaction_id: Option, + program_id: Option, + function_id: Option, + inputs: Vec, + transitions: Vec, + fee_transition: Option, + height: Option, + description: Option, + fee: Option, + visibility: Visibility, + error: Option, + ) -> Self { + Self { + _id, + event_type, + owner, + status, + created, + broadcast, + broadcast_height, + settled, + network, + transaction_id, + program_id, + function_id, + inputs, + transitions, + fee_transition, + height, + description, + fee, + visibility, + error, + } + } + + pub fn to_avail_event(&self) -> AvailEvent { + AvailEvent::new( + self._id.clone(), + self.event_type.clone(), + self.owner.clone(), + self.status.clone().to_transaction_state(), + self.created.clone(), + self.broadcast.clone(), + self.broadcast_height.clone(), + self.settled.clone(), + self.network.clone(), + self.transaction_id.clone(), + self.program_id.clone(), + self.function_id.clone(), + self.inputs.clone(), + self.transitions.clone(), + self.fee_transition.clone(), + self.height.clone(), + self.description.clone(), + self.fee.clone(), + self.visibility.clone(), + self.error.clone(), + None, + None, + None, + None, + ) + } + + pub fn get_created(&self) -> DateTime { + self.created + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct EventTransition { + #[serde(rename = "transitionId")] + transition_id: String, + #[serde(rename = "programId")] + program_id: String, + #[serde(rename = "functionId")] + function_id: String, + inputs: Vec, + outputs: Vec, +} + +impl EventTransition { + pub fn new( + transition_id: String, + program_id: String, + function_id: String, + inputs: Vec, + outputs: Vec, + ) -> Self { + Self { + transition_id, + program_id, + function_id, + inputs, + outputs, + } + } + + pub fn program_id(&self) -> &String { + &self.program_id + } + + pub fn function_id(&self) -> &String { + &self.function_id + } + + pub fn inputs(&self) -> Vec { + self.inputs.clone() + } +} + +/// Internal avail event used to display transaction history in a list +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +pub struct SuccinctAvailEvent { + id: String, + to: Option, + from: Option, + amount: Option, + fee: Option, + message: Option, + #[serde(rename = "type")] + event_type: EventTypeCommon, + status: TransactionState, + created: DateTime, + #[serde(rename = "programId")] + program_id: Option, + #[serde(rename = "functionId")] + function_id: Option, +} + +impl SuccinctAvailEvent { + pub fn new( + id: String, + to: Option, + from: Option, + amount: Option, + fee: Option, + message: Option, + event_type: EventTypeCommon, + status: TransactionState, + created: DateTime, + program_id: Option, + function_id: Option, + ) -> Self { + Self { + id, + to, + from, + amount, + fee, + message, + event_type, + status, + created, + program_id, + function_id, + } + } + + pub fn get_created(&self) -> DateTime { + self.created + } +} + +/// Internal avail event used to display a full event +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +pub struct AvailEvent { + _id: String, + #[serde(rename = "type")] + event_type: EventTypeCommon, + owner: String, + status: TransactionState, + created: DateTime, + broadcast: Option>, // finalized + #[serde(rename = "broadcastHeight")] + broadcast_height: Option, // finalized height + settled: Option>, // i.e confirmed + network: Network, + #[serde(rename = "transactionId")] + transaction_id: Option, + #[serde(rename = "programId")] + program_id: Option, + #[serde(rename = "functionId")] + function_id: Option, + inputs: Vec, + transitions: Vec, + fee_transition: Option, + height: Option, + description: Option, + fee: Option, + visibility: Visibility, // public or private + error: Option, + message: Option, + to: Option, + from: Option, + amount: Option, +} + +impl AvailEvent { + pub fn new( + _id: String, + event_type: EventTypeCommon, + owner: String, + status: TransactionState, + created: DateTime, + broadcast: Option>, + broadcast_height: Option, + settled: Option>, + network: Network, + transaction_id: Option, + program_id: Option, + function_id: Option, + inputs: Vec, + transitions: Vec, + fee_transition: Option, + height: Option, + description: Option, + fee: Option, + visibility: Visibility, + error: Option, + message: Option, + to: Option, + from: Option, + amount: Option, + ) -> Self { + Self { + _id, + event_type, + owner, + status, + created, + broadcast, + broadcast_height, + settled, + network, + transaction_id, + program_id, + function_id, + inputs, + transitions, + fee_transition, + height, + description, + fee, + visibility, + error, + message, + to, + from, + amount, + } + } + + pub fn get_created(&self) -> DateTime { + self.created + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub enum Network { + AleoTestnet, + AleoDevnet, + AleoMainnet, +} + +impl Network { + pub fn to_string(&self) -> String { + match self { + Network::AleoTestnet => "testnet3".to_string(), + Network::AleoDevnet => "devnet".to_string(), + Network::AleoMainnet => "mainnet".to_string(), + } + } + + pub fn from_str(s: &str) -> Option { + match s { + "testnet3" => Some(Network::AleoTestnet), + "devnet" => Some(Network::AleoDevnet), + "mainnet" => Some(Network::AleoMainnet), + _ => None, + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub enum Visibility { + Private, + Public, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TxScanResponse { + pub txs: bool, + pub block_height: u32, +} + +impl TxScanResponse { + pub fn new(txs: bool, block_height: u32) -> Self { + Self { txs, block_height } + } +} diff --git a/src-tauri/src/models/event_payloads.rs b/src-tauri/src/models/event_payloads.rs new file mode 100644 index 00000000..19993add --- /dev/null +++ b/src-tauri/src/models/event_payloads.rs @@ -0,0 +1,10 @@ +use serde::Serialize; + +#[derive(Serialize, Clone)] +pub struct ScanProgressPayload { + pub progress: f32, +} + +// TODO : Transaction execution event +// TODO : Transaction confirmed event +// TODO : Transaction failed event diff --git a/src-tauri/src/models/pointers.rs b/src-tauri/src/models/pointers.rs new file mode 100644 index 00000000..4b30c748 --- /dev/null +++ b/src-tauri/src/models/pointers.rs @@ -0,0 +1,5 @@ +pub mod deployment; +pub mod message; +pub mod record; +pub mod transaction; +pub mod transition; diff --git a/src-tauri/src/models/pointers/deployment.rs b/src-tauri/src/models/pointers/deployment.rs new file mode 100644 index 00000000..43de76e1 --- /dev/null +++ b/src-tauri/src/models/pointers/deployment.rs @@ -0,0 +1,377 @@ +use snarkvm::prelude::{Address, Network}; + +use chrono::{DateTime, Local}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::models::event::{ + AvailEvent, Event, Network as EventNetwork, SuccinctAvailEvent, Visibility, +}; +use crate::services::local_storage::{ + encrypted_data::store_encrypted_data, + persistent_storage::{get_address, get_address_string, get_network}, + session::view::VIEWSESSION, +}; +use crate::services::record_handling::utils::get_fee_transition; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::{ + encrypted_data::{ + EncryptedData, EncryptedDataRecord, EncryptedDataTypeCommon, EventTypeCommon, + TransactionState, + }, + traits::encryptable::{Encryptable, EncryptedStruct}, + }, +}; + +/// Deployment pointers are used to keep track of leo program deployment history +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DeploymentPointer { + pub id: Option, + pub program_id: String, + pub fee: f64, + pub state: TransactionState, + pub block_height: Option, + pub spent_fee_nonce: Option, + pub created: DateTime, + pub finalized: Option>, + pub error: Option, +} + +fn decrypt(encrypted_struct: EncryptedStruct) -> AvailResult> { + let view_key = VIEWSESSION.get_instance::()?; + let transition: DeploymentPointer = encrypted_struct.decrypt(view_key)?; + + Ok(transition) +} + +impl DeploymentPointer { + pub fn decrypt_x(encrypted_struct: EncryptedStruct) -> AvailResult> { + let view_key = VIEWSESSION.get_instance::()?; + let transition: DeploymentPointer = encrypted_struct.decrypt(view_key)?; + + Ok(transition) + } + + pub fn new( + id: Option, + program_id: String, + fee: f64, + state: TransactionState, + block_height: Option, + spent_fee_nonce: Option, + created: DateTime, + finalized: Option>, + error: Option, + ) -> Self { + Self { + id, + program_id, + fee, + state, + block_height, + spent_fee_nonce, + created, + finalized, + error, + } + } + + pub fn encrypt_and_store(&self, address: Address) -> AvailResult { + let encrypted_transaction = self.to_encrypted_data(address)?; + let id = match encrypted_transaction.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + store_encrypted_data(encrypted_transaction)?; + Ok(id) + } + + pub fn update_confirmed_deployment( + &mut self, + transaction_id: N::TransactionID, + block_height: u32, + fee: Option, + ) { + self.id = Some(transaction_id); + self.state = TransactionState::Confirmed; + self.block_height = Some(block_height); + self.finalized = Some(chrono::Local::now()); + self.fee = fee.unwrap_or(self.fee); + } + + pub fn update_pending_deployment(&mut self) { + self.state = TransactionState::Pending; + } + + pub fn update_failed_deployment(&mut self, error: String) { + self.state = TransactionState::Failed; + self.error = Some(error); + } + + pub fn update_rejected_deployment( + &mut self, + error: String, + transaction_id: Option, + block_height: u32, + fee: Option, + ) { + self.state = TransactionState::Rejected; + self.error = Some(error); + self.finalized = Some(chrono::Local::now()); + self.id = transaction_id; + self.block_height = Some(block_height); + self.fee = fee.unwrap_or(self.fee); + } + + pub fn update_aborted_deployment( + &mut self, + error: String, + transaction_id: N::TransactionID, + block_height: u32, + ) { + self.state = TransactionState::Aborted; + self.error = Some(error); + self.finalized = Some(chrono::Local::now()); + self.id = Some(transaction_id); + self.block_height = Some(block_height); + } + + pub fn update_cancelled_deployment(&mut self) { + self.state = TransactionState::Cancelled; + } + + pub fn to_encrypted_data_from_record( + encrypted_data_record: EncryptedDataRecord, + ) -> AvailResult { + let address = get_address::()?; + let encrypted_struct = encrypted_data_record.to_enrypted_struct::()?; + let record = decrypt::(encrypted_struct)?; + let encrypted_data = record.to_encrypted_data(address)?; + Ok(encrypted_data) + } + + pub fn to_encrypted_data(&self, encrypt_for: Address) -> AvailResult { + let encrypted_record_pointer = self.encrypt_for(encrypt_for)?; + + let network = get_network()?; + let id = Uuid::new_v4(); + let flavour = EncryptedDataTypeCommon::Deployment; + let created_at = chrono::Utc::now(); + + let encrypted_data = EncryptedData::new( + Some(id), + encrypt_for.to_string(), + encrypted_record_pointer.cipher_text.to_string(), + encrypted_record_pointer.nonce.to_string(), + flavour, + None, + Some(self.program_id.clone()), + None, + created_at, + None, + None, + network, + None, + None, + Some(EventTypeCommon::Deploy), + None, + Some(self.state.clone()), + ); + + Ok(encrypted_data) + } + + pub fn to_event(&self, id: &str) -> AvailResult { + let address = get_address_string()?; + let network = get_network()?; + let event_network = match EventNetwork::from_str(&network) { + Some(network) => network, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Network not found".to_string(), + "Network not found".to_string(), + )) + } + }; + + let tx_id = match &self.id { + Some(id) => Some(id.to_string()), + None => None, + }; + + let fee_transition = match &self.id { + Some(id) => match get_fee_transition::(*id) { + Ok(fee_transition) => Some(fee_transition), + Err(e) => return Err(e), + }, + None => None, + }; + + let event = Event::new( + id.to_string(), + EventTypeCommon::Deploy, + address, + self.state.to_event_status(), + self.created, + None, + None, + self.finalized, + event_network, + tx_id, + Some(self.program_id.clone()), + None, + vec![], + vec![], + fee_transition, + self.block_height, + None, + Some(self.fee), + Visibility::Public, + self.error.clone(), + ); + + Ok(event) + } + + pub fn to_avail_event(&self, id: &str) -> AvailResult { + let address = get_address_string()?; + let network = get_network()?; + let event_network = match EventNetwork::from_str(&network) { + Some(network) => network, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Network not found".to_string(), + "Network not found".to_string(), + )) + } + }; + + let tx_id = match &self.id { + Some(id) => Some(id.to_string()), + None => None, + }; + + let fee_transition = match &self.id { + Some(id) => match get_fee_transition::(*id) { + Ok(fee_transition) => Some(fee_transition), + Err(e) => return Err(e), + }, + None => None, + }; + + let event = AvailEvent::new( + id.to_string(), + EventTypeCommon::Deploy, + address, + self.state.clone(), + self.created, + None, + None, + self.finalized, + event_network, + tx_id, + Some(self.program_id.clone()), + None, + vec![], + vec![], + fee_transition, + self.block_height, + None, + Some(self.fee), + Visibility::Public, + self.error.clone(), + None, + None, + None, + None, + ); + + Ok(event) + } + + pub fn to_succinct_avail_event(&self, id: &str) -> AvailResult { + let event = SuccinctAvailEvent::new( + id.to_string(), + None, + None, + None, + Some(self.fee), + None, + EventTypeCommon::Deploy, + self.state.clone(), + self.created, + Some(self.program_id.clone()), + None, + ); + + Ok(event) + } + + pub fn decrypt_to_event(encrypted_transition: EncryptedData) -> AvailResult { + let v_key = VIEWSESSION.get_instance::()?; + + let db_id = match encrypted_transition.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + let encrypted_data = encrypted_transition.to_enrypted_struct::()?; + + let transition: DeploymentPointer = encrypted_data.decrypt(v_key)?; + + transition.to_event(&db_id) + } + + pub fn decrypt_to_avail_event(encrypted_deployment: EncryptedData) -> AvailResult { + let v_key = VIEWSESSION.get_instance::()?; + + let db_id = match encrypted_deployment.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + let encrypted_data = encrypted_deployment.to_enrypted_struct::()?; + + let deployment: DeploymentPointer = encrypted_data.decrypt(v_key)?; + + deployment.to_avail_event(&db_id) + } + + pub fn decrypt_to_succinct_avail_event( + encrypted_deployment: EncryptedData, + ) -> AvailResult { + let v_key = VIEWSESSION.get_instance::()?; + + let db_id = match encrypted_deployment.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + let encrypted_data = encrypted_deployment.to_enrypted_struct::()?; + + let deployment: DeploymentPointer = encrypted_data.decrypt(v_key)?; + + deployment.to_succinct_avail_event(&db_id) + } +} diff --git a/src-tauri/src/models/pointers/message.rs b/src-tauri/src/models/pointers/message.rs new file mode 100644 index 00000000..5cbb6560 --- /dev/null +++ b/src-tauri/src/models/pointers/message.rs @@ -0,0 +1,115 @@ +use chrono::{DateTime, Local}; +use serde::{Deserialize, Serialize}; +use snarkvm::prelude::{confirmed::ConfirmedTransaction, Address, Network}; +use uuid::Uuid; + +use crate::helpers::utils::get_timestamp_from_i64; +use crate::services::local_storage::{ + persistent_storage::get_network, storage_api::transaction::get_transaction_ids, +}; +use avail_common::{ + aleo_tools::api::AleoAPIClient, + errors::AvailResult, + models::{ + encrypted_data::{EncryptedData, EncryptedDataTypeCommon}, + traits::encryptable::Encryptable, + }, +}; + +use crate::api::aleo_client::setup_client; + +/// Encrypted and sent to the address the wallet owner interacted with in the transaction to avoid scanning times +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct TransactionMessage { + id: N::TransactionID, + confirmed_height: u32, + from: String, + message: Option, +} + +impl TransactionMessage { + pub fn new( + id: N::TransactionID, + confirmed_height: u32, + from: String, + message: Option, + ) -> Self { + Self { + id, + confirmed_height, + from, + message, + } + } + + pub fn id(&self) -> N::TransactionID { + self.id + } + + pub fn confirmed_height(&self) -> u32 { + self.confirmed_height + } + + pub fn from(&self) -> String { + self.from.to_owned() + } + + pub fn message(&self) -> Option { + self.message.to_owned() + } + + pub fn to_encrypted_data(&self, encrypt_for: Address) -> AvailResult { + let encrypted_tx_message = self.encrypt_for(encrypt_for)?; + let network = get_network()?; + + let _id = Uuid::new_v4(); + let flavour = EncryptedDataTypeCommon::TransactionMessage; + let created_at = chrono::Utc::now(); + + let encrypted_data = EncryptedData::new( + None, + encrypt_for.to_string(), + encrypted_tx_message.cipher_text.to_string(), + encrypted_tx_message.nonce.to_string(), + flavour, + None, + None, + None, + created_at, + None, + None, + network, + None, + None, + None, + None, + None, + ); + + Ok(encrypted_data) + } + + /// Checks if the transaction has been stored before and checks if the transaction is found at the confirmed block height + pub fn verify(&self) -> AvailResult<(Option>, DateTime)> { + let api_client = setup_client::()?; + + let block = api_client.get_block(self.confirmed_height)?; + let timestamp = get_timestamp_from_i64(block.timestamp())?; + + let stored_transaction_ids = get_transaction_ids::()?; + if stored_transaction_ids.contains(&self.id) { + return Ok((None, timestamp)); + } + + let tx_check = block.transactions().get(&self.id); + + match tx_check { + Some(tx) => { + return Ok((Some(tx.to_owned()), timestamp)); + } + None => { + return Ok((None, timestamp)); + } + } + } +} diff --git a/src-tauri/src/models/pointers/record.rs b/src-tauri/src/models/pointers/record.rs new file mode 100644 index 00000000..9334fd45 --- /dev/null +++ b/src-tauri/src/models/pointers/record.rs @@ -0,0 +1,255 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use snarkvm::prelude::{Address, Field, FromStr, Network, Plaintext, Record}; +use uuid::Uuid; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::{ + encrypted_data::{ + EncryptedData, EncryptedDataRecord, EncryptedDataTypeCommon, RecordTypeCommon, + }, + traits::encryptable::{Encryptable, EncryptedStruct}, + }, +}; + +use crate::api::aleo_client::setup_client; + +use crate::services::{ + local_storage::{ + persistent_storage::{get_address, get_network}, + session::view::VIEWSESSION, + }, + record_handling::utils::transition_to_record, +}; + +/// The record struct represents a pointer to a single record on the Aleo blockchain owned by the wallet account. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(bound = "N: Network")] +pub struct AvailRecord { + pub pointer: Pointer, + pub metadata: Metadata, +} + +fn decrypt(encrypted_struct: EncryptedStruct) -> AvailResult> { + let view_key = VIEWSESSION.get_instance::()?; + let record: AvailRecord = encrypted_struct.decrypt(view_key)?; + Ok(record) +} + +impl AvailRecord { + pub fn new(pointer: Pointer, metadata: Metadata) -> Self { + Self { pointer, metadata } + } + + pub fn to_encrypted_data_from_record( + encrypted_data_record: EncryptedDataRecord, + ) -> AvailResult { + let address = get_address::()?; + let encrypted_struct = encrypted_data_record.to_enrypted_struct::()?; + let record = decrypt::(encrypted_struct)?; + let encrypted_data = record.to_encrypted_data(address)?; + Ok(encrypted_data) + } + + pub fn to_encrypted_data(&self, encrypt_for: Address) -> AvailResult { + let encrypted_record_pointer = self.encrypt_for(encrypt_for)?; + let network = get_network()?; + + let id = Uuid::new_v4(); + let flavour = EncryptedDataTypeCommon::Record; + let created_at = chrono::Utc::now(); + + let encrypted_data = EncryptedData::new( + Some(id), + encrypt_for.to_string(), + encrypted_record_pointer.cipher_text.to_string(), + encrypted_record_pointer.nonce.to_string(), + flavour, + Some(self.metadata.record_type.clone()), + Some(self.metadata.program_id.clone()), + Some(self.metadata.function_id.clone()), + created_at, + None, + None, + network, + Some(self.metadata.name.clone()), + Some(self.metadata.spent), + None, + Some(self.metadata.nonce.clone()), + None, + ); + + Ok(encrypted_data) + } + + pub fn from_record( + commitment: Field, + record: &Record>, + sk_tag: Field, + record_type: RecordTypeCommon, + program_id: &str, + block_height: u32, + transaction_id: N::TransactionID, + transition_id: N::TransitionID, + function_id: &str, + name: String, + index: u8, + owner: &str, + ) -> AvailResult { + let tag = + match Record::>::tag(sk_tag, commitment) { + Ok(tag) => tag, + Err(e) => return Err(AvailError::new( + AvailErrorType::InvalidData, + "Error computing the record tag from sk_tag and commitment using record::tag()" + .to_string() + + &e.to_string(), + "Error forming record pointer, scan will restart at this height.".to_string(), + )), + }; + + let pointer = Pointer::new( + block_height, + transaction_id, + transition_id, + &commitment.to_string(), + &tag.to_string(), + index, + owner, + ); + + //TODO: V2-update to RecordTypeCommon::Tokens and have a token identification system (in progress) + let metadata = Metadata::new( + record_type, + program_id.to_string(), + function_id.to_string(), + false, + name, + record.nonce().to_string(), + ); + + Ok(Self::new(pointer, metadata)) + } + + pub fn to_record(&self) -> AvailResult>> { + let api_client = setup_client::()?; + + let record_transaction = api_client.get_transaction(self.pointer.transaction_id)?; + + let transition = match record_transaction.find_transition(&self.pointer.transition_id) { + Some(transition) => transition, + None => { + return Err(AvailError::new( + AvailErrorType::NotFound, + "Transition not found".to_string(), + "Transition not found".to_string(), + )) + } + }; + + let (record_plaintext, _record_ciphertext, _data) = + transition_to_record(transition, &self.pointer.commitment, self.pointer.index)?; + + Ok(record_plaintext) + } + + pub fn to_record_texts_and_data( + &self, + ) -> AvailResult<(String, String, HashMap)> { + let api_client = setup_client::()?; + + let record_transaction = api_client.get_transaction(self.pointer.transaction_id)?; + + let transition = match record_transaction.find_transition(&self.pointer.transition_id) { + Some(transition) => transition, + None => { + return Err(AvailError::new( + AvailErrorType::NotFound, + "Transition not found".to_string(), + "Transition not found".to_string(), + )) + } + }; + + let (record_plaintext, record_ciphertext, data) = + transition_to_record(transition, &self.pointer.commitment, self.pointer.index)?; + Ok(( + record_plaintext.to_string(), + record_ciphertext.to_string(), + data, + )) + } + + pub fn is_spent(&self) -> AvailResult { + Ok(self.metadata.spent) + } + + pub fn tag(&self) -> AvailResult> { + Ok(Field::::from_str(&self.pointer.tag)?) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct Pointer { + pub block_height: u32, + pub transaction_id: N::TransactionID, + pub transition_id: N::TransitionID, + pub commitment: String, + pub tag: String, + pub index: u8, + pub owner: String, +} + +impl Pointer { + pub fn new( + block_height: u32, + transaction_id: N::TransactionID, + transition_id: N::TransitionID, + commitment: &str, + tag: &str, + index: u8, + owner: &str, + ) -> Self { + Self { + block_height, + transaction_id, + transition_id, + commitment: commitment.to_string(), + tag: tag.to_string(), + index, + owner: owner.to_string(), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct Metadata { + pub record_type: RecordTypeCommon, + pub program_id: String, + pub function_id: String, + pub spent: bool, + pub name: String, + pub nonce: String, +} + +impl Metadata { + pub fn new( + record_type: RecordTypeCommon, + program_id: String, + function_id: String, + spent: bool, + name: String, + nonce: String, + ) -> Self { + Self { + record_type, + program_id, + function_id, + spent, + name, + nonce, + } + } +} diff --git a/src-tauri/src/models/pointers/transaction.rs b/src-tauri/src/models/pointers/transaction.rs new file mode 100644 index 00000000..595dd704 --- /dev/null +++ b/src-tauri/src/models/pointers/transaction.rs @@ -0,0 +1,660 @@ +use snarkvm::prelude::*; + +use chrono::{DateTime, Local}; +use serde::{Deserialize, Serialize}; +use std::fmt::{Display, Formatter, Result as Res}; +use uuid::Uuid; + +use crate::models::event::{ + AvailEvent, Event, EventTransition, Network as EventNetwork, SuccinctAvailEvent, Visibility, +}; + +use crate::{ + api::aleo_client::setup_client, + services::local_storage::{ + encrypted_data::store_encrypted_data, + persistent_storage::{get_address, get_address_string, get_network}, + session::view::VIEWSESSION, + }, + services::record_handling::{decrypt_transition::DecryptTransition, utils::get_fee_transition}, +}; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::{ + encrypted_data::{ + EncryptedData, EncryptedDataRecord, EncryptedDataTypeCommon, EventTypeCommon, + TransactionState, + }, + traits::encryptable::{Encryptable, EncryptedStruct}, + }, +}; + +/// Pointer to a transaction that has been executed by the wallet owner +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[serde(bound = "N: Network")] +pub struct TransactionPointer { + to: Option, + transaction_id: Option, + state: TransactionState, + block_height: Option, + executed_program_id: Option, + executed_function_id: Option, + transitions: Vec>, + spent_record_pointers_nonces: Vec, + created: DateTime, + finalized: Option>, + message: Option, + event_type: EventTypeCommon, + amount: Option, + fee: Option, + error: Option, +} + +fn decrypt(encrypted_struct: EncryptedStruct) -> AvailResult> { + let view_key = VIEWSESSION.get_instance::()?; + let transition: TransactionPointer = encrypted_struct.decrypt(view_key)?; + + Ok(transition) +} + +impl TransactionPointer { + #[allow(dead_code)] + pub fn new( + to: Option, + transaction_id: Option, + state: TransactionState, + block_height: Option, + executed_program_id: Option, + executed_function_id: Option, + transitions: Vec>, + spent_record_pointers_nonces: Vec, + created: DateTime, + finalized: Option>, + message: Option, + event_type: EventTypeCommon, + amount: Option, + fee: Option, + error: Option, + ) -> Self { + Self { + to, + transaction_id, + state, + block_height, + executed_program_id, + executed_function_id, + transitions, + spent_record_pointers_nonces, + created, + finalized, + message, + event_type, + amount, + fee, + error, + } + } + + #[allow(dead_code)] + pub fn to(&self) -> Option { + self.to.clone() + } + + pub fn transaction_id(&self) -> Option { + self.transaction_id + } + + #[allow(dead_code)] + pub fn state(&self) -> TransactionState { + self.state.clone() + } + + #[allow(dead_code)] + pub fn block_height(&self) -> Option { + self.block_height + } + + #[allow(dead_code)] + pub fn executed_program_id(&self) -> Option { + self.executed_program_id.clone() + } + + #[allow(dead_code)] + pub fn executed_function_id(&self) -> Option { + self.executed_function_id.clone() + } + + #[allow(dead_code)] + pub fn transitions(&self) -> Vec> { + self.transitions.clone() + } + + #[allow(dead_code)] + pub fn spent_record_pointers_nonces(&self) -> Vec { + self.spent_record_pointers_nonces.clone() + } + + pub fn created(&self) -> DateTime { + self.created + } + + pub fn finalized(&self) -> Option> { + self.finalized + } + + pub fn message(&self) -> Option { + self.message.clone() + } + + pub fn event_type(&self) -> EventTypeCommon { + self.event_type.clone() + } + + pub fn amount(&self) -> Option { + self.amount + } + + pub fn fee(&self) -> Option { + self.fee + } + + pub fn update_state(&mut self, state: TransactionState) { + self.state = state; + } + + pub fn error(&self) -> Option { + self.error.clone() + } + + pub fn update_confirmed_transaction( + &mut self, + transaction_id: N::TransactionID, + block_height: u32, + transitions: Vec>, + finalized: DateTime, + state: TransactionState, + fee: Option, + ) { + self.transaction_id = Some(transaction_id); + self.block_height = Some(block_height); + self.transitions = transitions; + self.finalized = Some(finalized); + self.state = state; + self.fee = fee; + } + + pub fn update_pending_transaction(&mut self) { + self.state = TransactionState::Pending; + } + + pub fn update_failed_transaction(&mut self, error: String) { + self.state = TransactionState::Failed; + self.error = Some(error); + self.fee = None; + } + + pub fn update_rejected_transaction( + &mut self, + error: String, + transaction_id: Option, + block_height: u32, + fee: Option, + ) { + self.state = TransactionState::Rejected; + self.error = Some(error); + self.finalized = Some(chrono::Local::now()); + self.transaction_id = transaction_id; + self.block_height = Some(block_height); + self.fee = fee; + } + + pub fn update_aborted_transaction( + &mut self, + error: String, + transaction_id: N::TransactionID, + block_height: u32, + ) { + self.state = TransactionState::Aborted; + self.error = Some(error); + self.finalized = Some(chrono::Local::now()); + self.transaction_id = Some(transaction_id); + self.block_height = Some(block_height); + self.fee = None; + } + + pub fn update_cancelled_transaction(&mut self) { + self.state = TransactionState::Cancelled; + } + + pub fn to_encrypted_data_from_record( + encrypted_data_record: EncryptedDataRecord, + ) -> AvailResult { + let address = get_address::()?; + let encrypted_struct = encrypted_data_record.to_enrypted_struct::()?; + let record = decrypt::(encrypted_struct)?; + let encrypted_data = record.to_encrypted_data(address)?; + Ok(encrypted_data) + } + + pub fn to_encrypted_data(&self, encrypt_for: Address) -> AvailResult { + let network = get_network()?; + let encrypted_tx = self.encrypt_for(encrypt_for)?; + + let id = Uuid::new_v4(); + let flavour = EncryptedDataTypeCommon::Transaction; + let created_at = chrono::Utc::now(); + + let program_ids = self + .transitions + .iter() + .map(|x| x.program_id.clone()) + .collect::>(); + let function_ids = self + .transitions + .iter() + .map(|x| x.function_id.clone()) + .collect::>(); + let json_program_ids = serde_json::to_string(&program_ids)?; + let json_function_ids = serde_json::to_string(&function_ids)?; + + let encrypted_data = EncryptedData::new( + Some(id), + encrypt_for.to_string(), + encrypted_tx.cipher_text.to_string(), + encrypted_tx.nonce.to_string(), + flavour, + None, + Some(json_program_ids), + Some(json_function_ids), + created_at, + None, + None, + network, + None, + None, + Some(self.event_type.clone()), + None, + Some(self.state.clone()), + ); + + Ok(encrypted_data) + } + + pub fn encrypt_and_store(&self, address: Address) -> AvailResult { + let encrypted_transaction = self.to_encrypted_data(address)?; + let id = match encrypted_transaction.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + store_encrypted_data(encrypted_transaction)?; + Ok(id) + } + + pub fn to_event(&self, id: &str) -> AvailResult { + let address = get_address_string()?; + let network = get_network()?; + + let event_network = match EventNetwork::from_str(&network) { + Some(network) => network, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Network not found".to_string(), + "Network not found".to_string(), + )) + } + }; + + let v_key = VIEWSESSION.get_instance::()?; + + let api_client = setup_client::()?; + + let event_transaction = match self.transaction_id { + Some(id) => match api_client.get_transaction(id) { + Ok(tx) => Some(tx), + Err(_) => { + return Err(AvailError::new( + AvailErrorType::Node, + "Transaction not found".to_string(), + "Transaction not found".to_string(), + )) + } + }, + None => None, + }; + + let transitions = match event_transaction { + Some(event_transaction) => match self + .transitions + .iter() + .map(|x| x.to_event_transition(v_key, &event_transaction)) + .collect::>>() + { + Ok(event_transitions) => event_transitions, + Err(e) => return Err(e), + }, + None => vec![], + }; + + let fee_transition = match self.transaction_id { + Some(id) => match get_fee_transition::(id) { + Ok(fee_transition) => Some(fee_transition), + Err(e) => return Err(e), + }, + None => None, + }; + + let tx_id_str = match self.transaction_id { + Some(id) => Some(id.to_string()), + None => None, + }; + + let root_inputs = match &self.executed_function_id { + Some(function_id) => { + match &self.executed_program_id { + Some(program_id) => { + // check if program id and function id match an event_transition and fetch the inputs as root_inputs + match transitions.iter().find(|x| { + x.program_id() == program_id && x.function_id() == function_id + }) { + Some(event_transition) => event_transition.inputs().clone(), + None => vec![], + } + } + None => vec![], + } + } + None => vec![], + }; + + let event = Event::new( + id.to_string(), + self.event_type.clone(), + address, + self.state.to_event_status(), + self.created, + None, + None, + self.finalized, + event_network, + tx_id_str, + self.executed_program_id.clone(), + self.executed_function_id.clone(), + root_inputs, + transitions, + fee_transition, + self.block_height, + None, + self.fee.clone(), + // TODO - Deduce visibility from transaction + Visibility::Private, + self.error.clone(), + ); + + Ok(event) + } + + pub fn to_avail_event(&self, id: &str) -> AvailResult { + let address = get_address_string()?; + let network = get_network()?; + + let event_network = match EventNetwork::from_str(&network) { + Some(network) => network, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Network not found".to_string(), + "Network not found".to_string(), + )) + } + }; + + let v_key = VIEWSESSION.get_instance::()?; + + let api_client = setup_client::()?; + + let event_transaction = match self.transaction_id { + Some(id) => match api_client.get_transaction(id) { + Ok(tx) => Some(tx), + Err(_) => { + return Err(AvailError::new( + AvailErrorType::Node, + "Transaction not found".to_string(), + "Transaction not found".to_string(), + )) + } + }, + None => None, + }; + + let transitions = match event_transaction { + Some(event_transaction) => match self + .transitions + .iter() + .map(|x| x.to_event_transition(v_key, &event_transaction)) + .collect::>>() + { + Ok(event_transitions) => event_transitions, + Err(e) => return Err(e), + }, + None => vec![], + }; + + let fee_transition = match self.transaction_id { + Some(id) => match get_fee_transition::(id) { + Ok(fee_transition) => Some(fee_transition), + Err(e) => return Err(e), + }, + None => None, + }; + + let tx_id_str = match self.transaction_id { + Some(id) => Some(id.to_string()), + None => None, + }; + + let root_inputs = match &self.executed_function_id { + Some(function_id) => { + match &self.executed_program_id { + Some(program_id) => { + // check if program id and function id match an event_transition and fetch the inputs as root_inputs + match transitions.iter().find(|x| { + x.program_id() == program_id && x.function_id() == function_id + }) { + Some(event_transition) => event_transition.inputs().clone(), + None => vec![], + } + } + None => vec![], + } + } + None => vec![], + }; + + let event = AvailEvent::new( + id.to_string(), + self.event_type.clone(), + address, + self.state.clone(), + self.created, + None, + None, + self.finalized, + event_network, + tx_id_str, + self.executed_program_id.clone(), + self.executed_function_id.clone(), + root_inputs, + transitions, + fee_transition, + self.block_height, + None, + self.fee.clone(), + Visibility::Private, + self.error.clone(), + self.message.clone(), + self.to.clone(), + None, + self.amount.clone(), + ); + + Ok(event) + } + + pub fn to_succinct_avail_event(&self, id: &str) -> AvailResult { + let event = SuccinctAvailEvent::new( + id.to_string(), + self.to.clone(), + None, + self.amount.clone(), + self.fee.clone(), + self.message.clone(), + self.event_type.clone(), + self.state.clone(), + self.created, + self.executed_program_id.clone(), + self.executed_function_id.clone(), + ); + + Ok(event) + } + + pub fn decrypt_to_event(encrypted_transition: EncryptedData) -> AvailResult { + let v_key = VIEWSESSION.get_instance::()?; + + let db_id = match encrypted_transition.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + let encrypted_data = encrypted_transition.to_enrypted_struct::()?; + + let transition: TransactionPointer = encrypted_data.decrypt(v_key)?; + + transition.to_event(&db_id) + } + + pub fn decrypt_to_avail_event(encrypted_transaction: EncryptedData) -> AvailResult { + let v_key = VIEWSESSION.get_instance::()?; + + let db_id = match encrypted_transaction.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + let encrypted_data = encrypted_transaction.to_enrypted_struct::()?; + + let transaction: TransactionPointer = encrypted_data.decrypt(v_key)?; + + transaction.to_avail_event(&db_id) + } + + pub fn decrypt_to_succinct_avail_event( + encrypted_transaction: EncryptedData, + ) -> AvailResult { + let v_key = VIEWSESSION.get_instance::()?; + + let db_id = match encrypted_transaction.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + let encrypted_data = encrypted_transaction.to_enrypted_struct::()?; + + let transaction: TransactionPointer = encrypted_data.decrypt(v_key)?; + + transaction.to_succinct_avail_event(&db_id) + } +} + +/// A transition executed by the wallet owner in a transaction +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct ExecutedTransition { + program_id: String, + function_id: String, + transition_id: N::TransitionID, +} + +impl ExecutedTransition { + pub fn new(program_id: String, function_id: String, transition_id: N::TransitionID) -> Self { + Self { + program_id, + function_id, + transition_id, + } + } + + pub fn program_id(&self) -> String { + self.program_id.clone() + } + + pub fn function_id(&self) -> String { + self.function_id.clone() + } + + pub fn transition_id(&self) -> N::TransitionID { + self.transition_id.clone() + } + + pub fn to_event_transition( + &self, + view_key: ViewKey, + transaction: &transaction::Transaction, + ) -> AvailResult { + let transition = match transaction.find_transition(&self.transition_id) { + Some(transition) => transition, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Transition not found".to_string(), + "Transition not found".to_string(), + )) + } + }; + + let (inputs, outputs) = DecryptTransition::decrypt_inputs_outputs(view_key, transition)?; + + let event_transition = EventTransition::new( + self.transition_id.to_string(), + self.program_id(), + self.function_id(), + inputs, + outputs, + ); + + Ok(event_transition) + } +} + +#[derive(Debug, Clone)] +pub struct TransferResponse { + pub(crate) transaction_id: N::TransactionID, + pub(crate) block_height: u32, + pub(crate) spent_input_commitment: String, + pub(crate) spent_fee_commitment: String, + pub(crate) pending_tx_id: String, +} + +impl Display for TransferResponse { + fn fmt(&self, f: &mut Formatter<'_>) -> Res { + write!(f, "tx_id: {} \n block_height: {} \n spent_input_commitment: {} \n spent_fee_commitment: {}", self.transaction_id,self.block_height,self.spent_input_commitment,self.spent_fee_commitment) + } +} diff --git a/src-tauri/src/models/pointers/transition.rs b/src-tauri/src/models/pointers/transition.rs new file mode 100644 index 00000000..9c482570 --- /dev/null +++ b/src-tauri/src/models/pointers/transition.rs @@ -0,0 +1,357 @@ +use avail_common::models::traits::encryptable::EncryptedStruct; +use chrono::{DateTime, Local}; +use serde::{Deserialize, Serialize}; +use snarkvm::prelude::{Address, Network}; +use uuid::Uuid; + +use crate::api::aleo_client::setup_client; +use crate::models::event::{ + AvailEvent, Event, EventTransition, Network as EventNetwork, SuccinctAvailEvent, Visibility, +}; +use crate::services::local_storage::{ + persistent_storage::{get_address, get_address_string, get_network}, + session::view::VIEWSESSION, +}; +use crate::services::record_handling::decrypt_transition::DecryptTransition; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::{ + encrypted_data::{ + EncryptedData, EncryptedDataRecord, EncryptedDataTypeCommon, EventStatus, + EventTypeCommon, TransactionState, + }, + traits::encryptable::Encryptable, + }, +}; + +// Pointer to a transition the wallet owner has received from or been a part of +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TransitionPointer { + pub id: N::TransitionID, + pub transaction_id: N::TransactionID, + pub program_id: String, + pub function_id: String, + pub timestamp: DateTime, + pub transition_type: TransitionType, + pub message: Option, + pub from: Option, + pub amount: Option, + pub block_height: u32, +} + +fn decrypt(encrypted_struct: EncryptedStruct) -> AvailResult> { + let view_key = VIEWSESSION.get_instance::()?; + let transition: TransitionPointer = encrypted_struct.decrypt(view_key)?; + + Ok(transition) +} + +impl TransitionPointer { + pub fn new( + id: N::TransitionID, + transaction_id: N::TransactionID, + program_id: String, + function_id: String, + timestamp: DateTime, + transition_type: TransitionType, + message: Option, + from: Option, + amount: Option, + block_height: u32, + ) -> Self { + Self { + id, + transaction_id, + program_id, + function_id, + timestamp, + transition_type, + message, + from, + amount, + block_height, + } + } + + pub fn to_encrypted_data(&self, encrypt_for: Address) -> AvailResult { + let encrypted_record_pointer = self.encrypt_for(encrypt_for)?; + + let network = get_network()?; + let id = Uuid::new_v4(); + let flavour = EncryptedDataTypeCommon::Transition; + let created_at = chrono::Utc::now(); + + let encrypted_data = EncryptedData::new( + Some(id), + encrypt_for.to_string(), + encrypted_record_pointer.cipher_text.to_string(), + encrypted_record_pointer.nonce.to_string(), + flavour, + None, + Some(self.program_id.clone()), + Some(self.function_id.clone()), + created_at, + None, + None, + network, + None, + None, + Some(self.transition_type.to_event_type()), + None, + None, + ); + + Ok(encrypted_data) + } + + pub fn to_encrypted_data_from_record( + encrypted_data_record: EncryptedDataRecord, + ) -> AvailResult { + let address = get_address::()?; + let encrypted_struct = encrypted_data_record.to_enrypted_struct::()?; + let record = decrypt::(encrypted_struct)?; + let encrypted_data = record.to_encrypted_data(address)?; + Ok(encrypted_data) + } + + pub fn to_event(&self, id: &str) -> AvailResult { + let address = get_address_string()?; + let network = get_network()?; + let event_network = match EventNetwork::from_str(&network) { + Some(network) => network, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Network not found".to_string(), + "Network not found".to_string(), + )) + } + }; + + let api_client = setup_client::()?; + let transaction = api_client.get_transaction(self.transaction_id)?; + + let transition = match transaction.find_transition(&self.id) { + Some(transition) => transition, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Transition not found".to_string(), + "Transition not found".to_string(), + )) + } + }; + + let view_key = VIEWSESSION.get_instance::()?; + + let (inputs, outputs) = DecryptTransition::decrypt_inputs_outputs(view_key, transition)?; + + let event_transition = EventTransition::new( + self.id.to_string(), + self.program_id.clone(), + self.function_id.clone(), + inputs.clone(), + outputs, + ); + + let event = Event::new( + id.to_string(), + self.transition_type.to_event_type(), + address, + EventStatus::Settled, + self.timestamp, + None, + None, + None, + event_network, + Some(self.transaction_id.to_string()), + Some(self.program_id.clone()), + Some(self.function_id.clone()), + inputs, + vec![event_transition], + None, + None, + None, + None, + Visibility::Private, + None, + ); + + Ok(event) + } + + pub fn to_avail_event(&self, id: &str) -> AvailResult { + let address = get_address_string()?; + let network = get_network()?; + let event_network = match EventNetwork::from_str(&network) { + Some(network) => network, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Network not found".to_string(), + "Network not found".to_string(), + )) + } + }; + + let api_client = setup_client::()?; + + let transaction = api_client.get_transaction(self.transaction_id)?; + + let transition = match transaction.find_transition(&self.id) { + Some(transition) => transition, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Transition not found".to_string(), + "Transition not found".to_string(), + )) + } + }; + + let view_key = VIEWSESSION.get_instance::()?; + + let (inputs, outputs) = DecryptTransition::decrypt_inputs_outputs(view_key, transition)?; + + let event_transition = EventTransition::new( + self.id.to_string(), + self.program_id.clone(), + self.function_id.clone(), + inputs.clone(), + outputs, + ); + + //TODO - Fix Visibility + let event = AvailEvent::new( + id.to_string(), + self.transition_type.to_event_type(), + address, + TransactionState::Confirmed, + self.timestamp, + None, + None, + None, + event_network, + Some(self.transaction_id.to_string()), + Some(self.program_id.clone()), + Some(self.function_id.clone()), + inputs, + vec![event_transition], + None, + None, + None, + None, + Visibility::Private, + None, + self.message.clone(), + None, + self.from.clone(), + self.amount.clone(), + ); + + Ok(event) + } + + pub fn to_succinct_avail_event(&self, id: &str) -> AvailResult { + let event = SuccinctAvailEvent::new( + id.to_string(), + None, + self.from.clone(), + self.amount.clone(), + None, + self.message.clone(), + self.transition_type.to_event_type(), + TransactionState::Confirmed, + self.timestamp, + Some(self.program_id.clone()), + Some(self.function_id.clone()), + ); + + Ok(event) + } + + pub fn decrypt_to_event(encrypted_transition: EncryptedData) -> AvailResult { + let v_key = VIEWSESSION.get_instance::()?; + + let db_id = match encrypted_transition.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + let encrypted_data = encrypted_transition.to_enrypted_struct::()?; + + let transition: TransitionPointer = encrypted_data.decrypt(v_key)?; + + transition.to_event(&db_id) + } + + pub fn decrypt_to_avail_event(encrypted_transition: EncryptedData) -> AvailResult { + let v_key = VIEWSESSION.get_instance::()?; + + let db_id = match encrypted_transition.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + let encrypted_data = encrypted_transition.to_enrypted_struct::()?; + + let transition: TransitionPointer = encrypted_data.decrypt(v_key)?; + + transition.to_avail_event(&db_id) + } + + pub fn decrypt_to_succinct_avail_event( + encrypted_transition: EncryptedData, + ) -> AvailResult { + let v_key = VIEWSESSION.get_instance::()?; + + let db_id = match encrypted_transition.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + let encrypted_data = encrypted_transition.to_enrypted_struct::()?; + + let transition: TransitionPointer = encrypted_data.decrypt(v_key)?; + + transition.to_succinct_avail_event(&db_id) + } + + pub fn is_fee(&self) -> bool { + match self.transition_type { + TransitionType::Fee => true, + _ => false, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum TransitionType { + Input, + Output, + Event, + Fee, +} + +impl TransitionType { + pub fn to_event_type(&self) -> EventTypeCommon { + match self { + TransitionType::Input => EventTypeCommon::Send, + TransitionType::Output => EventTypeCommon::Receive, + _ => EventTypeCommon::Execute, // fees + } + } +} diff --git a/src-tauri/src/models/storage/encryption.rs b/src-tauri/src/models/storage/encryption.rs new file mode 100644 index 00000000..82397fc6 --- /dev/null +++ b/src-tauri/src/models/storage/encryption.rs @@ -0,0 +1,48 @@ +#![allow(dead_code)] + +use std::fmt::Display; + +use snarkvm::{console::prelude::*, prelude::*}; + +pub enum EncryptedData { + PrivateKey, + ViewKey, +} + +#[derive(PartialEq, Eq, Debug)] +pub enum Keys { + PrivateKey(PrivateKey), + ViewKey(ViewKey), +} + +impl Keys { + pub fn to_bytes_le(&self) -> Result, Error> { + match self { + Keys::PrivateKey(key) => key.to_bytes_le(), + Keys::ViewKey(key) => key.to_bytes_le(), + } + } + + pub fn is_private_key(&self) -> Option> { + match self { + Keys::PrivateKey(pk) => Some(*pk), + Keys::ViewKey(_) => None, + } + } + + pub fn is_view_key(&self) -> Option> { + match self { + Keys::PrivateKey(_) => None, + Keys::ViewKey(vk) => Some(*vk), + } + } +} + +impl Display for Keys { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Keys::PrivateKey(key) => write!(f, "{}", key), + Keys::ViewKey(key) => write!(f, "{}", key), + } + } +} diff --git a/src-tauri/src/models/storage/languages.rs b/src-tauri/src/models/storage/languages.rs new file mode 100644 index 00000000..e6561d4b --- /dev/null +++ b/src-tauri/src/models/storage/languages.rs @@ -0,0 +1,84 @@ +use bip39::Language; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum Languages { + English, + ChineseSimplified, + ChineseTraditional, + Russian, + Spanish, + Italian, + Turkish, + Estonian, + Lithuanian, + Latvian, + Dutch, + Japanese, +} + +impl Languages { + pub fn to_string(&self) -> String { + match self { + Languages::English => "English".to_string(), + Languages::ChineseSimplified => "Chinese Simplified".to_string(), + Languages::ChineseTraditional => "Chinese Traditional".to_string(), + Languages::Russian => "Russian".to_string(), + Languages::Spanish => "Spanish".to_string(), + Languages::Italian => "Italian".to_string(), + Languages::Turkish => "Turkish".to_string(), + Languages::Estonian => "Estonian".to_string(), + Languages::Lithuanian => "Lithuanian".to_string(), + Languages::Latvian => "Latvian".to_string(), + Languages::Dutch => "Dutch".to_string(), + Languages::Japanese => "Japanese".to_string(), + } + } + + pub fn to_string_short(&self) -> String { + match self { + Languages::English => "en".to_string(), + Languages::ChineseSimplified => "zh-cn".to_string(), + Languages::ChineseTraditional => "zh-tw".to_string(), + Languages::Russian => "ru".to_string(), + Languages::Spanish => "es".to_string(), + Languages::Italian => "it".to_string(), + Languages::Turkish => "tr".to_string(), + Languages::Estonian => "et".to_string(), + Languages::Lithuanian => "lt".to_string(), + Languages::Latvian => "lv".to_string(), + Languages::Dutch => "nl".to_string(), + Languages::Japanese => "ja".to_string(), + } + } + + pub fn from_string_short(s: &str) -> Option { + match s { + "en" => Some(Languages::English), + "zh-cn" => Some(Languages::ChineseSimplified), + "zh-tw" => Some(Languages::ChineseTraditional), + "ru" => Some(Languages::Russian), + "es" => Some(Languages::Spanish), + "it" => Some(Languages::Italian), + "tr" => Some(Languages::Turkish), + "et" => Some(Languages::Estonian), + "lt" => Some(Languages::Lithuanian), + "lv" => Some(Languages::Latvian), + "nl" => Some(Languages::Dutch), + "ja" => Some(Languages::Japanese), + _ => None, + } + } + + pub fn to_bip39_language(&self) -> Language { + match self { + Languages::English => Language::English, + Languages::ChineseSimplified => Language::ChineseSimplified, + Languages::ChineseTraditional => Language::ChineseTraditional, + Languages::Spanish => Language::Spanish, + Languages::Italian => Language::Italian, + Languages::Japanese => Language::Japanese, + _ => Language::English, + } + } +} diff --git a/src-tauri/src/models/storage/mod.rs b/src-tauri/src/models/storage/mod.rs new file mode 100644 index 00000000..68d20e5e --- /dev/null +++ b/src-tauri/src/models/storage/mod.rs @@ -0,0 +1,3 @@ +pub mod encryption; +pub mod languages; +pub mod persistent; diff --git a/src-tauri/src/models/storage/persistent.rs b/src-tauri/src/models/storage/persistent.rs new file mode 100644 index 00000000..15ad0a26 --- /dev/null +++ b/src-tauri/src/models/storage/persistent.rs @@ -0,0 +1,132 @@ +use app_dirs::*; +use rusqlite::{ + params_from_iter, + types::{FromSql, ToSql}, + Connection, +}; + +use avail_common::errors::AvailResult; + +pub struct PersistentStorage { + pub conn: Connection, + db_path: String, +} + +impl PersistentStorage { + ///Creates a new instance of PersistentStorage + pub fn new() -> AvailResult { + let path = app_root( + AppDataType::UserData, + &AppInfo { + name: "avail_wallet", + author: "Avail", + }, + )?; + + let db_path = path.into_os_string().into_string().unwrap(); + + let conn = Connection::open(format!("{}/persistent.db", db_path))?; + + Ok(PersistentStorage { conn, db_path }) + } + + /// Create a table within the database with an SQL query + pub fn execute_query(&self, query: &str) -> AvailResult<()> { + self.conn.execute(query, ())?; + + Ok(()) + } + + /// Save a vector of items of the same type to a table within the database with an SQL query + pub fn save(&self, data: Vec, query: String) -> AvailResult<()> { + let _insert = self.conn.execute( + &query, + //map data to params i.e data -> item1, item2 .. + params_from_iter(data.into_iter()), + )?; + + Ok(()) + } + + // Save a vector of items to a table within the database with an SQL query and allow for different types + pub fn save_mixed(&self, data: Vec<&dyn ToSql>, query: String) -> AvailResult<()> { + let _insert = self.conn.execute( + &query, + //map data to params i.e data -> item1, item2 .. + params_from_iter(data.into_iter()), + )?; + + Ok(()) + } + + /// Fetch a vector of items of the same type from a table within the database with an SQL query + pub fn get(&self, query: String, item_count: usize) -> AvailResult> { + let mut statement = self.conn.prepare(&query)?; + + let mut key_iter = statement.query_map([], |row| { + let data: Vec = (0..item_count).flat_map(|i| row.get(i)).collect(); + + Ok(data) + })?; + + let vec = key_iter.next().unwrap().unwrap(); + + Ok(vec) + } + + /// Fetch a vector of items of the same type from a table within the database with an SQL query + pub fn get_all(&self, query: &str, item_count: usize) -> AvailResult>> { + let mut statement = self.conn.prepare(query)?; + + let key_iter = statement.query_map([], |row| { + let data = (0..item_count).flat_map(|i| row.get(i)).collect(); + Ok(data) + })?; + + let key_vec = key_iter + .map(|key| match key { + Ok(key) => key, + Err(_) => Vec::new(), + }) + .collect::>>(); + + Ok(key_vec) + } +} +#[test] +fn test_save() { + let storage = PersistentStorage::new().unwrap(); + + //create table test + let query = "CREATE TABLE IF NOT EXISTS test (name TEXT, color TEXT)"; + + let _res = storage.execute_query(query).unwrap(); + + let query = "INSERT INTO test (name, color) VALUES (?, ?)".to_string(); + + let data = vec!["test".to_string(), "blue".to_string()]; + + let _res = storage.save(data, query).unwrap(); + + //then test getting data from the database + let query = "SELECT name, color FROM test".to_string(); + + let res = storage.get::(query, 2).unwrap(); + + assert_eq!(res[0], "test".to_string()); + assert_eq!(res[1], "blue".to_string()); +} + +#[test] +fn test_get() { + let storage = PersistentStorage::new().unwrap(); + //then test getting data from the database + let query = "SELECT name, color FROM test".to_string(); + + let res = storage.get::(query, 2).unwrap(); + + print!("{:?}", res); + + assert_eq!(res[0], "test".to_string()); + assert_eq!(res[1], "blue".to_string()); +} diff --git a/src-tauri/src/models/transfer.rs b/src-tauri/src/models/transfer.rs new file mode 100644 index 00000000..0b4e1ae4 --- /dev/null +++ b/src-tauri/src/models/transfer.rs @@ -0,0 +1,83 @@ +use avail_common::aleo_tools::program_manager::TransferType; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct TransferRequest { + recipient: String, + amount: u64, + message: Option, + password: Option, + transfer_type: u8, + fee_private: bool, + fee: u64, + asset_id: String, +} + +impl TransferRequest { + pub fn new( + recipient: String, + amount: u64, + message: Option, + password: Option, + transfer_type: TransferType, + fee_private: bool, + fee: u64, + asset_id: String, + ) -> Self { + let transfer_type = match transfer_type { + TransferType::Public => 0, + TransferType::Private => 1, + TransferType::PublicToPrivate => 2, + TransferType::PrivateToPublic => 3, + }; + + Self { + recipient, + amount, + message, + password, + transfer_type, + fee_private, + fee, + asset_id, + } + } + + pub fn recipient(&self) -> &String { + &self.recipient + } + + pub fn amount(&self) -> &u64 { + &self.amount + } + + pub fn message(&self) -> &Option { + &self.message + } + + pub fn password(&self) -> &Option { + &self.password + } + + pub fn transfer_type(&self) -> &TransferType { + match &self.transfer_type { + 0 => &TransferType::Public, + 1 => &TransferType::Private, + 2 => &TransferType::PublicToPrivate, + 3 => &TransferType::PrivateToPublic, + _ => &TransferType::Private, + } + } + + pub fn fee_private(&self) -> &bool { + &self.fee_private + } + + pub fn fee(&self) -> &u64 { + &self.fee + } + + pub fn asset_id(&self) -> &String { + &self.asset_id + } +} diff --git a/src-tauri/src/models/wallet.rs b/src-tauri/src/models/wallet.rs new file mode 100644 index 00000000..79ce1f6e --- /dev/null +++ b/src-tauri/src/models/wallet.rs @@ -0,0 +1,269 @@ +use bip39::{Mnemonic, MnemonicType, Seed}; +use snarkvm::{ + console::prelude::*, + prelude::{Address, PrivateKey, ViewKey}, +}; + +use avail_common::errors::{AvailError, AvailResult}; +use zeroize::Zeroize; + +use crate::models::storage::languages::Languages; + +#[derive(Debug)] +pub struct BetterAvailWallet { + pub address: Address, + pub view_key: ViewKey, + pub private_key: PrivateKey, + pub mnemonic: Option, +} + +impl PartialEq for BetterAvailWallet { + fn eq(&self, other: &Self) -> bool { + self.private_key == other.private_key + && self.address == other.address + && self.view_key == other.view_key + } +} + +impl Eq for BetterAvailWallet {} + +impl BetterAvailWallet { + /// Generates a new [`BetterAvailWallet`], whilst throwing an error if the seed phrase length is not 12, 15, 18, 21, or 24. + /// + /// ``` + /// use availx_lib::models::wallet::BetterAvailWallet; + /// # use availx_lib::models::storage::languages::Languages; + /// # use snarkvm::prelude::Testnet3; + /// + /// let wallet = BetterAvailWallet::::new(24, &Languages::English); + /// + /// assert!(wallet.is_ok()); + /// ``` + pub fn new(seed_phrase_len: usize, seed_lang: &Languages) -> AvailResult { + let mnemonic = Mnemonic::new( + MnemonicType::for_word_count(seed_phrase_len)?, + Languages::to_bip39_language(seed_lang), + ); + + // NOTE: EMPTY BECAUSE WE ARE NOT USING PASSWORDS FOR SPs + let seed = Seed::new(&mnemonic, ""); + + Self::from_mnemonic_seed(seed, mnemonic) + } + + /// This method returns the bytes of the [`Field`] used to derive an Aleo [(docs)](https://developer.aleo.org/concepts/accounts#create-an-account) [`PrivateKey`]. + /// + /// Not to be confused with [`Seed`]. + pub fn get_seed_bytes(&self) -> AvailResult> { + let seed_bytes = self.private_key.to_bytes_le()?; + + Ok(seed_bytes) + } + + /// Generates an [`AvailWallet`] from an arbitrary seed phrase, using the specified [`Language`]. + pub fn from_seed_phrase(seed_phrase: &str, lang: bip39::Language) -> AvailResult { + let mnemonic = Mnemonic::from_phrase(seed_phrase, lang)?; + let seed = Seed::new(&mnemonic, ""); + + Self::from_mnemonic_seed(seed, mnemonic) + } + + /// Generates a [`BetterAvailWallet`] from the [`Seed`] of a [`Mnemonic`]. + pub fn from_mnemonic_seed(seed: Seed, mnemonic: Mnemonic) -> AvailResult { + let bytes = &mut seed.as_bytes()[0..=32].to_vec(); + + let field = ::Field::from_bytes_le_mod_order(bytes); + + let private_key = + PrivateKey::::try_from(FromBytes::read_le(&*field.to_bytes_le().unwrap()).unwrap())?; + + bytes.zeroize(); + + let view_key = ViewKey::::try_from(&private_key)?; + let address = Address::::try_from(&private_key)?; + + Ok(BetterAvailWallet:: { + address, + view_key, + private_key, + mnemonic: Some(mnemonic), + }) + } + + /// Gets the private key string of an avail wallet. + pub fn get_private_key(&self) -> String { + self.private_key.to_string() + } + + /// Gets the view key string of an avail wallet. + pub fn get_view_key(&self) -> String { + self.view_key.to_string() + } + + /// Gets the address string of an avail wallet. + pub fn get_address(&self) -> String { + self.address.to_string() + } + + pub fn get_network(&self) -> String { + N::NAME.to_string() + } +} + +/// Implementing the `Display` trait for the `BetterAvailWallet` struct. +impl Display for BetterAvailWallet { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.private_key) + } +} + +/// Implementing the `TryFrom` trait for the `BetterAvailWallet` struct. +impl TryFrom for BetterAvailWallet { + type Error = AvailError; + + fn try_from(value: String) -> AvailResult { + let private_key = PrivateKey::::from_str(&value)?; + let view_key = ViewKey::::try_from(&private_key)?; + let address = Address::::try_from(&private_key)?; + + Ok(BetterAvailWallet:: { + address, + view_key, + private_key, + mnemonic: None, + }) + } +} + +impl TryFrom<&str> for BetterAvailWallet { + type Error = AvailError; + + fn try_from(value: &str) -> AvailResult { + let private_key = PrivateKey::::from_str(value)?; + let view_key = ViewKey::::try_from(&private_key)?; + let address = Address::::try_from(&private_key)?; + + Ok(BetterAvailWallet:: { + address, + view_key, + private_key, + mnemonic: None, + }) + } +} + +impl TryFrom> for BetterAvailWallet { + type Error = AvailError; + + fn try_from(value: PrivateKey) -> AvailResult { + let view_key = ViewKey::::try_from(&value)?; + let address = Address::::try_from(&value)?; + + Ok(BetterAvailWallet:: { + address, + view_key, + private_key: value, + mnemonic: None, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rstest::rstest; + use snarkvm::prelude::Testnet3; + + const PRIVATE_KEY: &str = "APrivateKey1zkpDqSfXcDcHdsvjkQhzF4NHTPPC63CBRHyaarTP3NAcHvg"; + const PHRASE: &str = "brave pass marine truly lecture fancy rail exotic destroy health always thunder wife decide situate index secret enter cruise prosper pudding about barely quit"; + + #[rstest] + fn test_create_random_avail_wallet(#[values(12, 15, 18, 21, 24)] seed_phrase_len: usize) { + let wallet = BetterAvailWallet::::new(seed_phrase_len, &Languages::English); + + assert!(wallet.is_ok()); + + let wallet = wallet.unwrap(); + println!("Wallet: {}", wallet.get_private_key()); + } + + #[rstest] + fn test_from_seed_bytes(#[values(12, 15, 18, 21, 24)] seed_phrase_len: usize) { + let mnemonic = Mnemonic::new( + MnemonicType::for_word_count(seed_phrase_len).unwrap(), + Languages::to_bip39_language(&Languages::English), + ); + + assert_eq!(mnemonic.phrase().split(" ").count(), seed_phrase_len); + + let seed = Seed::new(&mnemonic, ""); + let bytes = &mut seed.as_bytes()[0..32].to_vec(); + + assert_eq!(bytes.len(), 32); + + let wallet = BetterAvailWallet::::from_mnemonic_seed(seed, mnemonic); + + assert!(wallet.is_ok()); + } + + #[rstest] + /// Test that a wallet can be created from the seed phrase. + fn test_get_seed_bytes(#[values(12, 15, 18, 21, 24)] seed_phrase_len: usize) { + let wallet = + BetterAvailWallet::::new(seed_phrase_len, &Languages::English).unwrap(); + let seed_bytes = wallet.get_seed_bytes().unwrap(); + + assert_eq!(seed_bytes.len(), 32); + } + + #[rstest] + /// Test that an avail wallet can be created from the seed phrase. + fn test_from_seed_phrase() { + let mnemonic = Mnemonic::from_phrase(PHRASE, bip39::Language::English).unwrap(); + + let seed_phrase = mnemonic.phrase(); + + let wallet = BetterAvailWallet::::from_seed_phrase( + seed_phrase, + Languages::to_bip39_language(&Languages::English), + ); + + assert!(wallet.is_ok()); + + let wallet = wallet.unwrap(); + + assert_eq!(wallet.get_private_key(), PRIVATE_KEY) + } + + #[rstest] + /// Test that the private key string can be retrieved from the avail wallet. + fn test_get_private_key() { + let wallet = BetterAvailWallet::::try_from(PRIVATE_KEY).unwrap(); + let private_key = wallet.get_private_key(); + + assert_eq!(private_key, PRIVATE_KEY); + } + + #[rstest] + /// Test that the address string can be retrieved from the avail wallet. + fn test_get_view_key() { + let wallet = BetterAvailWallet::::try_from(PRIVATE_KEY).unwrap(); + let view_key = wallet.get_view_key(); + + assert_eq!( + view_key, + "AViewKey1icabKrKXiTjKnk1fd2p8NZ9etV8KZKNrejtiaHnav34N" + ); + } + + #[rstest] + fn test_get_address() { + let wallet = BetterAvailWallet::::try_from(PRIVATE_KEY).unwrap(); + let address = wallet.get_address(); + + assert_eq!( + address, + "aleo1lavuvpvklv3fdjwesr4pp5wekq2gjahu00krprnx8c2wc5xepuyqv64xk8" + ) + } +} diff --git a/src-tauri/src/models/wallet_connect.rs b/src-tauri/src/models/wallet_connect.rs new file mode 100644 index 00000000..679d27f9 --- /dev/null +++ b/src-tauri/src/models/wallet_connect.rs @@ -0,0 +1,6 @@ +pub mod balance; +pub mod create_event; +pub mod decrypt; +pub mod get_event; +pub mod records; +pub mod sign; diff --git a/src-tauri/src/models/wallet_connect/balance.rs b/src-tauri/src/models/wallet_connect/balance.rs new file mode 100644 index 00000000..a244e4fe --- /dev/null +++ b/src-tauri/src/models/wallet_connect/balance.rs @@ -0,0 +1,82 @@ +use serde::{Deserialize, Serialize}; + +/* Balance Interfaces */ + +#[derive(Serialize, Deserialize, Debug)] +pub struct Balance { + public: f64, + private: f64, +} + +impl Balance { + pub fn public(&self) -> f64 { + self.public + } + + pub fn private(&self) -> f64 { + self.private + } + + pub fn total(&self) -> f64 { + self.public + self.private + } + + pub fn total_string(&self) -> String { + self.total().to_string() + } + + pub fn new(public: f64, private: f64) -> Self { + Self { public, private } + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct BalanceResponse { + balances: Vec, + error: Option, +} + +impl BalanceResponse { + pub fn new(balances: Vec, error: Option) -> Self { + Self { balances, error } + } + + pub fn balances(&self) -> &Vec { + &self.balances + } + + pub fn error(&self) -> Option<&String> { + self.error.as_ref() + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct BalanceRequest { + #[serde(rename = "assetId")] + asset_id: Option, + address: Option, +} + +impl BalanceRequest { + pub fn new(asset_id: Option<&str>, address: Option<&str>) -> Self { + let asset_id = match asset_id { + Some(asset_id) => Some(asset_id.to_string()), + None => None, + }; + + let address = match address { + Some(address) => Some(address.to_string()), + None => None, + }; + + Self { asset_id, address } + } + + pub fn asset_id(&self) -> Option { + self.asset_id.clone() + } + + pub fn address(&self) -> Option { + self.address.clone() + } +} diff --git a/src-tauri/src/models/wallet_connect/create_event.rs b/src-tauri/src/models/wallet_connect/create_event.rs new file mode 100644 index 00000000..adab6bbb --- /dev/null +++ b/src-tauri/src/models/wallet_connect/create_event.rs @@ -0,0 +1,80 @@ +use avail_common::models::encrypted_data::EventTypeCommon; +use serde::{Deserialize, Serialize}; +/* Create Event Interfaces */ + +#[derive(Serialize, Deserialize, Debug)] +pub struct CreateEventRequest { + address: Option, + #[serde(rename = "type")] + event_type: EventTypeCommon, + #[serde(rename = "programId")] + program_id: String, + #[serde(rename = "functionId")] + function_id: String, + fee: f64, + inputs: Vec, +} + +impl CreateEventRequest { + pub fn new( + address: Option, + event_type: EventTypeCommon, + program_id: String, + function_id: String, + fee: f64, + inputs: Vec, + ) -> Self { + Self { + address, + event_type, + program_id, + function_id, + fee, + inputs, + } + } + + pub fn address(&self) -> Option<&String> { + self.address.as_ref() + } + + pub fn event_type(&self) -> &EventTypeCommon { + &self.event_type + } + + pub fn program_id(&self) -> &String { + &self.program_id + } + + pub fn function_id(&self) -> &String { + &self.function_id + } + + pub fn fee(&self) -> f64 { + self.fee + } + + pub fn inputs(&self) -> &Vec { + &self.inputs + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct CreateEventResponse { + event_id: Option, + error: Option, +} + +impl CreateEventResponse { + pub fn new(event_id: Option, error: Option) -> Self { + Self { event_id, error } + } + + pub fn event_id(&self) -> Option<&String> { + self.event_id.as_ref() + } + + pub fn error(&self) -> Option<&String> { + self.error.as_ref() + } +} diff --git a/src-tauri/src/models/wallet_connect/decrypt.rs b/src-tauri/src/models/wallet_connect/decrypt.rs new file mode 100644 index 00000000..11ba5ed8 --- /dev/null +++ b/src-tauri/src/models/wallet_connect/decrypt.rs @@ -0,0 +1,24 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct DecryptRequest { + pub ciphertexts: Vec, +} + +impl DecryptRequest { + pub fn new(ciphertexts: Vec) -> Self { + Self { ciphertexts } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct DecryptResponse { + plaintexts: Vec, + error: Option, +} + +impl DecryptResponse { + pub fn new(plaintexts: Vec, error: Option) -> Self { + Self { plaintexts, error } + } +} diff --git a/src-tauri/src/models/wallet_connect/deploy.rs b/src-tauri/src/models/wallet_connect/deploy.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src-tauri/src/models/wallet_connect/deploy.rs @@ -0,0 +1 @@ + diff --git a/src-tauri/src/models/wallet_connect/get_event.rs b/src-tauri/src/models/wallet_connect/get_event.rs new file mode 100644 index 00000000..6d5810c5 --- /dev/null +++ b/src-tauri/src/models/wallet_connect/get_event.rs @@ -0,0 +1,123 @@ +use crate::models::event::{AvailEvent, Event}; +use avail_common::models::encrypted_data::EventTypeCommon; +use serde::{Deserialize, Serialize}; + +/* Get Event Interfaces */ +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct GetEventRequest { + pub id: String, + pub address: Option, +} + +impl GetEventRequest { + pub fn new(id: String, address: Option) -> Self { + Self { id, address } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct GetEventResponse { + pub event: Option, + pub error: Option, +} + +impl GetEventResponse { + pub fn new(event: Option, error: Option) -> Self { + Self { event, error } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct GetAvailEventResponse { + pub event: Option, + pub error: Option, +} + +impl GetAvailEventResponse { + pub fn new(event: Option, error: Option) -> Self { + Self { event, error } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct GetEventsRequest { + pub filter: Option, + pub page: Option, +} + +impl GetEventsRequest { + pub fn default() -> Self { + Self { + filter: Some(EventsFilter::default()), + page: Some(0), + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct EventsFilter { + #[serde(rename = "type")] + pub event_type: Option, + #[serde(rename = "programId")] + pub program_id: Option, + #[serde(rename = "functionId")] + pub function_id: Option, +} + +impl EventsFilter { + pub fn new( + event_type: Option, + program_id: Option, + function_id: Option, + ) -> Self { + Self { + event_type, + program_id, + function_id, + } + } + + pub fn default() -> Self { + Self { + event_type: None, + program_id: None, + function_id: None, + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct GetEventsResponse { + pub events: Vec, + #[serde(rename = "pageCount")] + pub page_count: Option, + pub error: Option, +} + +impl GetEventsResponse { + pub fn new(events: Vec, page_count: Option, error: Option) -> Self { + Self { + events, + page_count, + error, + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct GetAvailEventsResponse { + pub events: Vec, + #[serde(rename = "pageCount")] + pub page_count: Option, + pub error: Option, +} + +impl GetAvailEventsResponse { + pub fn new(events: Vec, page_count: Option, error: Option) -> Self { + Self { + events, + page_count, + error, + } + } +} diff --git a/src-tauri/src/models/wallet_connect/records.rs b/src-tauri/src/models/wallet_connect/records.rs new file mode 100644 index 00000000..e9286172 --- /dev/null +++ b/src-tauri/src/models/wallet_connect/records.rs @@ -0,0 +1,203 @@ +use crate::models::pointers::record::AvailRecord; +use avail_common::errors::AvailResult; +use serde::{Deserialize, Serialize}; +use snarkvm::console::program::Network; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct GetRecordsRequest { + address: Option, + filter: Option, + page: Option, +} + +impl GetRecordsRequest { + pub fn new(address: Option, filter: Option, page: Option) -> Self { + Self { + address, + filter, + page, + } + } + pub fn address(&self) -> &Option { + &self.address + } + + pub fn filter(&self) -> &Option { + &self.filter + } + + pub fn page(&self) -> &Option { + &self.page + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct RecordsFilter { + #[serde(rename = "programIds")] + program_ids: Vec, + #[serde(rename = "functionId")] + function_id: Option, + #[serde(rename = "type")] + record_type: String, + record_name: Option, +} + +impl RecordsFilter { + pub fn new( + program_ids: Vec, + function_id: Option, + record_type: RecordFilterType, + record_name: Option, + ) -> Self { + Self { + program_ids, + function_id, + record_type: record_type.to_string(), + record_name, + } + } + + pub fn program_ids(&self) -> &Vec { + &self.program_ids + } + + pub fn function_id(&self) -> &Option { + &self.function_id + } + + pub fn record_type(&self) -> &String { + &self.record_type + } + + pub fn record_name(&self) -> &Option { + &self.record_name + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum RecordFilterType { + All, + Spent, + Unspent, +} + +impl RecordFilterType { + pub fn from_str(filter: &str) -> Self { + match filter { + "all" => RecordFilterType::All, + "spent" => RecordFilterType::Spent, + "unspent" => RecordFilterType::Unspent, + _ => RecordFilterType::All, + } + } + + pub fn to_string(&self) -> String { + match self { + RecordFilterType::All => "all".to_string(), + RecordFilterType::Spent => "spent".to_string(), + RecordFilterType::Unspent => "unspent".to_string(), + } + } + + pub fn from_string(filter: &String) -> &Self { + match filter.as_str() { + "all" => &RecordFilterType::All, + "spent" => &RecordFilterType::Spent, + "unspent" => &RecordFilterType::Unspent, + _ => &RecordFilterType::All, + } + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct GetRecordsResponse { + records: Vec, + #[serde(rename = "pageCount")] + page_count: Option, + error: Option, +} + +impl GetRecordsResponse { + pub fn new( + records: Vec, + page_count: Option, + error: Option, + ) -> Self { + Self { + records, + page_count, + error, + } + } + + pub fn records(&self) -> &Vec { + &self.records + } + + pub fn page_count(&self) -> &Option { + &self.page_count + } + + pub fn error(&self) -> &Option { + &self.error + } +} + +// A new struct for RecordWithPlaintext +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct RecordWithPlaintext { + pub record: wc_Record, + pub plaintext: String, + pub data: std::collections::HashMap, +} + +impl RecordWithPlaintext { + pub fn from_record_pointer( + record_pointer: AvailRecord, + id: String, + ) -> AvailResult { + let (plaintext, ciphertext, data) = record_pointer.to_record_texts_and_data()?; + + let record = wc_Record { + _id: id, + event_id: record_pointer.pointer.transaction_id.to_string(), + height: record_pointer.pointer.block_height, + ciphertext, + program_id: record_pointer.metadata.program_id, + function_id: record_pointer.metadata.function_id, + transition_id: record_pointer.pointer.transition_id.to_string(), + transaction_id: record_pointer.pointer.transaction_id.to_string(), + owner: record_pointer.pointer.owner, + spent: record_pointer.metadata.spent, + serial_number: None, + name: record_pointer.metadata.name, + }; + Ok(Self { + record, + plaintext, + data, + }) + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct wc_Record { + pub _id: String, // transaction id or commitment + #[serde(rename = "eventId")] + pub event_id: String, // transaction id + pub height: u32, + pub ciphertext: String, + #[serde(rename = "programId")] + pub program_id: String, + #[serde(rename = "functionId")] + pub function_id: String, + #[serde(rename = "transitionId")] + pub transition_id: String, + #[serde(rename = "transactionId")] + pub transaction_id: String, + pub owner: String, + pub spent: bool, + #[serde(rename = "serialNumber")] + pub serial_number: Option, // Fetch in .to_record() + pub name: String, +} diff --git a/src-tauri/src/models/wallet_connect/sign.rs b/src-tauri/src/models/wallet_connect/sign.rs new file mode 100644 index 00000000..7dbce9fd --- /dev/null +++ b/src-tauri/src/models/wallet_connect/sign.rs @@ -0,0 +1,55 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SignatureRequest { + message: String, + address: Option, +} + +impl SignatureRequest { + pub fn new(message: String, address: Option) -> Self { + Self { message, address } + } + + pub fn get_message(&self) -> String { + self.message.clone() + } + + pub fn get_address(&self) -> Option { + self.address.clone() + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SignatureResponse { + signature: Option, + #[serde(rename = "messageFields")] + message_fields: Option, + error: Option, +} + +impl SignatureResponse { + pub fn new( + signature: Option, + message_fields: Option, + error: Option, + ) -> Self { + Self { + signature, + message_fields, + error, + } + } + + pub fn get_signature(&self) -> Option { + self.signature.clone() + } + + pub fn get_message_fields(&self) -> Option { + self.message_fields.clone() + } + + pub fn get_error(&self) -> Option { + self.error.clone() + } +} diff --git a/src-tauri/src/services.rs b/src-tauri/src/services.rs new file mode 100644 index 00000000..05b0ad84 --- /dev/null +++ b/src-tauri/src/services.rs @@ -0,0 +1,6 @@ +pub mod account; +pub mod authentication; +pub mod local_storage; +pub mod record_handling; +pub mod records; +pub mod wallet_connect_api; diff --git a/src-tauri/src/services/README.md b/src-tauri/src/services/README.md new file mode 100644 index 00000000..06762268 --- /dev/null +++ b/src-tauri/src/services/README.md @@ -0,0 +1,43 @@ +# Services Documentation + +## Overview + +This is the logic behind Avail wallet, this encapsulates account creation, handling of transactions and records, wallet recovery using shamir's secret sharing scheme and storing on the android/ios secure enclaves. + +## Services + +### generation.rs + +This is the initial generation of a wallet for a user. The wallet can either be without a seed phrase or with a seed phrase, if they have a seed phrase then they dont't make use of our recovery system. + +The user inputs a username and passoword and chooses if they would like to authenticate using biometrics. Once inputted an aleo keypair is generated and the local storage process starts, along with the sharding as preperation in case of recovery. The user can also choose to allow others to reference them by their username and in that case we store the username and address in Avail's database. + +### local_storage + +#### iOS + + For iOS we use the iOS keychain, a secure data storage system made by apple, to store the private key and this is protected either by the application password or biometrics. The private key is encrypted by an aes-key generated and stored in the keychain's secure enclave and this is non extractable. + + We use apple's `security-framework` and `local-authentication-framework` to access the keychain and authnetication functionalities. + +#### Android + +For android we use the android keystore, a secure data storage system made by google. This generates and stores a cryptographic key AES | RSA in a TEE (Trusted Execution Environment) or secure enclave to protect it from extraction. The key is protected by biometrics. Then we encrypt the private key and viewing key using the key in the keystore and store it in the android shared preferences. + +In the case of authenticating the user with application password, we hash the password using argon2, generate an aes key from the derived password hash and use that to encrypt a randomly generated aes-key. With the randomly generated aes-key we encrypt the private key and viewing key and store it an sqlite database embeded in the user's application data. The password hash is not stored locally and must be inputted by the user to authenticate and use the keys. + +### recovery.rs + +This process is only available to those who opt in and do kyc verification so we can prove their identity when they want to recover their wallet. + +Using Shamir's secret sharing scheme we split the private key into 3 encrypted shards and these are sent to three entities. These entities are the user's cloud, either iCloud keychain or Gdrive, Avail's secure data storage and our partner's secure data storage. Shamir is set in a way that 2 of the 3 shards is sufficient to reconstruct the original private key. + +By default the user's cloud and Avail's secure data storage is used for recovery. When a user wants to recover they do kyc verification and if verified the shard is sent from Avail to the user. Then the shards are reconstructed and the private key is stored locally on the user's device as explained in the local_storage section. + +If the shard is not present in the user's specified cloud then we must make use of the partner's secure data storage. Again in this case the user must do kyc verification and input their email address and if verified then recovery will start. We make it clear that in our system only one encrypted shard is ever being transferred using https. Therefore the user will receive two random emails along the following hours and each email will take them to the Avail app and initiate the recovery of a shard in that instance. This is done for security purposes, once both shards are recovered the private key is reconstructed and stored locally on the user's device as explained in the local_storage section. + +We will move research and develop a solution that stills verify the user without kyc as we move forward and innovate in the future. + +### records.rs + +This is the logic behind handling the records of the user locally i.e getting the user's balance and past transaction and filtering the transactions. Also this includes the transfer function allowing to send tokens to someone else on the aleo network.This is done using the aleo rust sdk. diff --git a/src-tauri/src/services/account.rs b/src-tauri/src/services/account.rs new file mode 100644 index 00000000..40910d35 --- /dev/null +++ b/src-tauri/src/services/account.rs @@ -0,0 +1,4 @@ +pub mod generation; +pub mod key_management; +pub mod phrase_recovery; +pub mod utils; diff --git a/src-tauri/src/services/account/generation.rs b/src-tauri/src/services/account/generation.rs new file mode 100644 index 00000000..ed77904d --- /dev/null +++ b/src-tauri/src/services/account/generation.rs @@ -0,0 +1,159 @@ +use snarkvm::{console::prelude::*, prelude::Testnet3}; + +use crate::models::storage::languages::Languages; +use crate::services::account::{ + key_management::key_controller::KeyController, utils::generate_discriminant, +}; +use crate::services::authentication::session::get_session_after_creation; +use crate::services::local_storage::persistent_storage::get_language; +use crate::services::local_storage::{ + encrypted_data::{get_and_store_all_data, initialize_encrypted_data_table}, + persistent_storage::initial_user_preferences, + session::{password::PASS, view::VIEWSESSION}, + tokens::init_tokens_table, +}; +use crate::{api::user::create_user, models::wallet::BetterAvailWallet}; + +#[cfg(target_os = "linux")] +use crate::services::account::key_management::key_controller::linuxKeyController; + +#[cfg(target_os = "windows")] +use crate::services::account::key_management::key_controller::windowsKeyController; + +#[cfg(target_os = "macos")] +use crate::services::account::key_management::key_controller::macKeyController; + +use avail_common::{errors::AvailResult, models::user::User}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn create_seed_phrase_wallet( + username: Option, + password: String, + access_type: bool, + backup: bool, + language: Languages, + length: usize, +) -> AvailResult { + let avail_wallet = BetterAvailWallet::::new(length, &language)?; + + let tag = username.clone().map(|_| generate_discriminant()); + + let user_request = User { + username: username.clone(), + address: avail_wallet.address.to_string(), + tag, + backup: false, + }; + + create_user(user_request).await?; + + //TODO: Change to mainnet on launch + initial_user_preferences( + access_type, + username, + tag, + false, + backup, + avail_wallet.address.to_string(), + language.clone(), + )?; + + init_tokens_table()?; + + initialize_encrypted_data_table()?; + + let key_manager = { + #[cfg(target_os = "windows")] + { + windowsKeyController {} + } + #[cfg(target_os = "linux")] + { + linuxKeyController {} + } + #[cfg(target_os = "macos")] + { + macKeyController {} + } + }; + + key_manager.store_key(&password, &avail_wallet)?; + + VIEWSESSION.set_view_session(&avail_wallet.get_view_key())?; + + PASS.set_pass_session(&password)?; + + get_session_after_creation(&avail_wallet.private_key).await?; + + // NOTE: We can safely unwrap here because we created + // the wallet using the [`BetterAvailWallet::new`] method + let seed_phrase = avail_wallet.mnemonic.unwrap().phrase().to_string(); + + Ok(seed_phrase) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn import_wallet( + username: Option, + password: String, + access_type: bool, + private_key: &str, + backup: bool, + language: Languages, +) -> AvailResult { + let avail_wallet = BetterAvailWallet::::try_from(private_key.to_string())?; + + let tag = username.clone().map(|_| generate_discriminant()); + + let user_request = User { + username: username.clone(), + address: avail_wallet.address.to_string(), + tag, + backup: false, + }; + + create_user(user_request).await?; + + initial_user_preferences( + access_type, + username, + tag, + false, + backup, + avail_wallet.address.to_string(), + language, + )?; + + init_tokens_table()?; + + initialize_encrypted_data_table()?; + + let key_manager = { + #[cfg(target_os = "windows")] + { + windowsKeyController {} + } + + #[cfg(target_os = "linux")] + { + linuxKeyController {} + } + + #[cfg(target_os = "macos")] + { + macKeyController {} + } + }; + + let storage = key_manager.store_key(&password, &avail_wallet)?; + + VIEWSESSION.set_view_session(&avail_wallet.view_key.to_string())?; + + PASS.set_pass_session(&password)?; + + get_session_after_creation(&avail_wallet.private_key).await?; + + get_and_store_all_data().await?; + + Ok(storage) +} diff --git a/src-tauri/src/services/account/key_management.rs b/src-tauri/src/services/account/key_management.rs new file mode 100644 index 00000000..866508bc --- /dev/null +++ b/src-tauri/src/services/account/key_management.rs @@ -0,0 +1,2 @@ +pub mod desktop; +pub mod key_controller; diff --git a/src-tauri/src/services/account/key_management/android.rs b/src-tauri/src/services/account/key_management/android.rs new file mode 100644 index 00000000..899609b6 --- /dev/null +++ b/src-tauri/src/services/account/key_management/android.rs @@ -0,0 +1,719 @@ +use avail_common::models::network::SupportedNetworks; +use jni::objects::{JByteArray, JClass, JMap, JObject, JString, JValue}; + +use jni::{JNIEnv, JavaVM}; +use ndk_context; +use snarkvm::prelude::*; +use std::ffi::c_void; + +use crate::api::{encrypted_data::delete_all_server_storage, user::delete_user}; + +use crate::models::{ + auth::Options, + storage::encryption::{EncryptedData, Keys, Keys::PrivateKey as PKey, Keys::ViewKey as VKey}, + wallet::AvailWallet, +}; + +use crate::services::local_storage::{ + persistent_storage::{ + delete_user_preferences, get_auth_type, get_network, remove_view_session, + }, + records_storage::delete_user_encrypted_data, + utils::encrypt_with_password, +}; + +use avail_common::{ + aleo_tools::encryptor::Encryptor, + errors::{AvailError, AvailErrorType, AvailResult}, +}; + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "system" fn Java_com_example_keystore_KeyStoreModule_create( + mut env: JNIEnv, + class: JClass, + alias: JString, + p_key: JByteArray, + v_key: JByteArray, + options: JObject, + context: JObject, +) -> AvailResult<()> { + let j_context = JValue::Object(&context); + print!("Error cause of params?"); + let keystore_module = env.new_object(class, "(Landroid/content/Context;)V", &[j_context])?; + + let keystore_module_ref = env.new_global_ref(keystore_module)?; + + let j_alias = JValue::Object(&alias); + let j_pkey = JValue::Object(&p_key); + let j_vkey = JValue::Object(&v_key); + let j_options = JValue::Object(&options); + + let result = env.call_method( + keystore_module_ref, + "setGenericPassword", + "(Ljava/lang/String;[B[BLjava/util/Map;Landroid/content/Context;)Ljava/util/Map;", + &[j_alias, j_pkey, j_vkey, j_options, j_context], + )?; + + let exceptions = env.exception_occurred()?; + + if exceptions.is_null() { + println!("No exception occurred"); + } else { + println!("Exception occurred"); + env.exception_describe()?; + env.exception_clear()?; + } + + let result = result.l()?; + + println!("{:#?}", result); + Ok(()) +} + +#[allow(non_snake_case)] +pub extern "system" fn Java_com_example_keystore_KeyStoreModule_get( + mut env: JNIEnv, + class: JClass, + alias: JString, + options: JObject, + context: JObject, + key_type: JString, +) -> AvailResult> { + let j_context = JValue::Object(&context); + + let keystore_module = env.new_object(class, "(Landroid/content/Context;)V", &[j_context])?; + + let keystore_module_ref = env.new_global_ref(keystore_module)?; + + let j_alias = JValue::Object(&alias); + let j_options = JValue::Object(&options); + let j_key_type = JValue::Object(&key_type); + + let result = env.call_method( + keystore_module_ref, + "getGenericPassword", + "(Ljava/lang/String;Ljava/util/Map;Landroid/content/Context;Ljava/lang/String;)Ljava/util/Map;", + &[j_alias, j_options, j_context, j_key_type], + )?; + + let exceptions = env.exception_occurred()?; + if exceptions.is_null() { + println!("No exception occurred"); + } else { + println!("Exception occurred"); + env.exception_describe()?; + env.exception_clear()?; + } + + let result = result.l()?; + + //turn result to map then iterate through map to get values which are bytes + + let JMap = JMap::from_env(&mut env, &result)?; + + let mut iter = JMap.iter(&mut env)?; + + // there will be two key value pairs in the map, one for username and one for password + + let p_key_value = iter.next(&mut env)?; + + let p_key_value = match p_key_value { + Some(p) => p, + None => { + return Err(AvailError::new( + AvailErrorType::LocalStorage, + "No key value pair found".to_string(), + "No key value pair found".to_string(), + )) + } + }; + + let v_key_value = iter.next(&mut env)?; + + let v_key_value = match v_key_value { + Some(v) => v, + None => { + return Err(AvailError::new( + AvailErrorType::LocalStorage, + "No key value pair found".to_string(), + "No key value pair found".to_string(), + )) + } + }; + + let key_raw = p_key_value.1.as_raw(); + let key = unsafe { JByteArray::from_raw(key_raw) }; + let p_key = env.convert_byte_array(key)?; + + let key_raw = v_key_value.1.as_raw(); + let key = unsafe { JByteArray::from_raw(key_raw) }; + let v_key = env.convert_byte_array(key)?; + + // println!("PKbytes {:?}", p_key); + // print!("VKbytes {:?}", v_key); + + let key_type = env.get_string(&key_type)?; + let key_type = key_type.to_str(); + + let key_type = match key_type { + Ok(k) => k, + Err(_e) => { + return Err(AvailError::new( + AvailErrorType::LocalStorage, + "Error converting key type".to_string(), + "Error converting key type".to_string(), + )) + } + }; + match key_type { + "avl-p" => Ok(p_key), + "avl-v" => Ok(v_key), + _ => Err(AvailError::new( + AvailErrorType::InvalidData, + "Invalid key type".to_string(), + "Invalid key type".to_string(), + )), + } +} + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "system" fn Java_com_example_keystore_KeyStoreModule_delete( + mut env: JNIEnv, + class: JClass, + alias: JString, + context: JObject, +) -> AvailResult<()> { + let j_context = JValue::Object(&context); + + let keystore_module = env.new_object(class, "(Landroid/content/Context;)V", &[j_context])?; + + let keystore_module_ref = env.new_global_ref(keystore_module)?; + + let j_alias = JValue::Object(&alias); + + let _result = env.call_method( + keystore_module_ref, + "resetGenericPassword", + "(Ljava/lang/String;)Z", + &[j_alias], + )?; + + let exceptions = env.exception_occurred()?; + + if exceptions.is_null() { + println!("No exception occurred"); + } else { + println!("Exception occurred"); + env.exception_describe()?; + env.exception_clear()?; + }; + + Ok(()) +} + +/// Checks if the device supports biometric authentication using jni +#[no_mangle] +#[allow(non_snake_case)] +pub extern "system" fn Java_com_example_keystore_KeyStoreModule_check( + mut env: JNIEnv, + class: JClass, + context: JObject, +) -> AvailResult { + let j_context = JValue::Object(&context); + + let keystore_module = env.new_object(class, "(Landroid/content/Context;)V", &[j_context])?; + + let keystore_module_ref = env.new_global_ref(keystore_module)?; + + let result = env.call_method( + keystore_module_ref, + "checkBio", + "(Landroid/content/Context;)Z", + &[j_context], + )?; + + let exceptions = env.exception_occurred()?; + + if exceptions.is_null() { + println!("No exception occurred"); + } else { + println!("Exception occurred"); + env.exception_describe()?; + env.exception_clear()?; + } + + Ok(result.z()?) +} + +/// Checks if the app has permission to use biometric authentication +#[no_mangle] +#[allow(non_snake_case)] +pub extern "system" fn Java_com_example_keystore_KeyStoreModule_permission( + mut env: JNIEnv, + class: JClass, + context: JObject, +) -> AvailResult { + let j_context = JValue::Object(&context); + + let keystore_module = env.new_object(class, "(Landroid/content/Context;)V", &[j_context])?; + + let keystore_module_ref = env.new_global_ref(keystore_module)?; + + let result = env.call_method( + keystore_module_ref, + "checkBiometryPermission", + "(Landroid/content/Context;)Z", + &[j_context], + )?; + + let exceptions = env.exception_occurred()?; + + if exceptions.is_null() { + println!("No exception occurred"); + } else { + println!("Exception occurred"); + env.exception_describe()?; + env.exception_clear()?; + } + + Ok(result.z()?) +} + +/// Creates a JVM instance and returns a tuple of the JVM and the activity context +fn prepare_jvm() -> AvailResult<(JavaVM, *mut c_void)> { + let ctx = ndk_context::android_context(); + let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }?; + + let activity = ctx.context(); + + Ok((vm, activity)) +} + +// TODO: Collect common code -> Having problems with lifetimes and borrowing + +///Creates or loads an instance of keystore, generating a protected RSA Key and stores +///encrypted username, encrypted password and salt in SharedPreferences. +#[tauri::command(rename_all = "snake_case")] +pub fn keystore_init( + password: &str, + access_type: bool, + p_key: &PrivateKey, + v_key: &ViewKey, +) -> AvailResult { + let mut auth_options = Options::default(); + + if access_type { + println!("Biometric access enabled"); + auth_options.accessControl = Some("BiometryCurrentSet".to_string()); + }; + + let (jvm, activity) = prepare_jvm()?; + + let _env = jvm.attach_current_thread()?; + + let mut env = jvm.get_env()?; + + let class = env.find_class("com/example/keystore/KeyStoreModule")?; + + let class2 = **class; + let class2 = unsafe { JClass::from_raw(class2) }; + + let service = env.new_string(auth_options.service)?; + let title = env.new_string(auth_options.title)?; + let subtitle = env.new_string(auth_options.subtitle)?; + let description = env.new_string(auth_options.description)?; + let cancel = env.new_string(auth_options.cancel)?; + let accessible = env.new_string(auth_options.accessible)?; + let security_level = env.new_string(auth_options.securityLevel)?; + + let mut access_control = JObject::from(env.new_string("None")?); + let acc = auth_options.accessControl; + + if let Some(a) = acc { + access_control = JObject::from(env.new_string(a)?); + } + + let mut storage = JObject::from(env.new_string("Best")?); + let sto = auth_options.storage; + + if let Some(s) = sto { + storage = JObject::from(env.new_string(s)?); + } + + let mut authentication_type = JObject::null(); + let aut = auth_options.authenticationType; + + if let Some(a) = aut { + authentication_type = JObject::from(env.new_string(a)?); + } + + let jservice = JValue::Object(&service); + let jtitle = JValue::Object(&title); + let jsubtitle = JValue::Object(&subtitle); + let jdescription = JValue::Object(&description); + let jcancel = JValue::Object(&cancel); + let jaccessible = JValue::Object(&accessible); + let jaccess_control = JValue::Object(&access_control); + let jstorage = JValue::Object(&storage); + let jsecurity_level = JValue::Object(&security_level); + let jauthentication_type = JValue::Object(&authentication_type); + + let result = env.call_static_method(class, "constructOptions", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/util/Map;", + &[jservice, jtitle, jsubtitle, jdescription, jcancel, jaccessible, jaccess_control, jstorage, jsecurity_level, jauthentication_type])?; + + let exceptions = env.exception_occurred()?; + + if exceptions.is_null() { + println!("No exception occurred"); + } else { + println!("Exception occurred"); + env.exception_describe()?; + env.exception_clear()?; + } + + let options = result.l()?; + + let alias = env.new_string("AV_KEYSTORE")?; + + let context = unsafe { JObject::from_raw(activity as jni::sys::jobject) }; + + match access_type { + true => { + let p_key = env.byte_array_from_slice(&p_key.to_bytes_le()?)?; + let v_key = env.byte_array_from_slice(&v_key.to_bytes_le()?)?; + Java_com_example_keystore_KeyStoreModule_create( + env, class2, alias, p_key, v_key, options, context, + )?; + } + false => { + let network = get_network()?; + print!("Got here son"); + let ciphertext_p = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + match encrypt_with_password::(password, PKey(*p_key)) { + Ok(c) => c, + Err(e) => { + println!("Error encrypting view key: {}", e); + return Err(AvailError::new( + AvailErrorType::Internal, + "Error encrypting private key".to_string(), + "Error encrypting private key".to_string(), + )); + } + } + } + }; + + let ciphertext_v = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + match encrypt_with_password::(password, VKey(*v_key)) { + Ok(c) => c, + Err(e) => { + println!("Error encrypting view key: {}", e); + return Err(AvailError::new( + AvailErrorType::Internal, + "Error encrypting view key".to_string(), + "Error encrypting view key".to_string(), + )); + } + } + } + }; + + let p_key = env.byte_array_from_slice(&ciphertext_p.to_bytes_le()?)?; + let v_key = env.byte_array_from_slice(&ciphertext_v.to_bytes_le()?)?; + + Java_com_example_keystore_KeyStoreModule_create( + env, class2, alias, p_key, v_key, options, context, + )?; + } + } + + Ok("Key stored".to_string()) +} + +///Uses the key in keystore to decrypt the hash stored in SharedPreferences. +#[tauri::command(rename_all = "snake_case")] +pub fn keystore_load(password: Option<&str>, key_type: &str) -> AvailResult> { + let auth_options = Options::default(); + let auth_type = get_auth_type()?; + + if !auth_type { + let _pass = password.ok_or(AvailError::new( + AvailErrorType::Internal, + "Login".to_string(), + "Login".to_string(), + ))?; + }; + + let (jvm, activity) = prepare_jvm()?; + + jvm.attach_current_thread()?; + + let mut env = jvm.get_env()?; + + let class = env.find_class("com/example/keystore/KeyStoreModule")?; + + let class2 = **class; + let class2 = unsafe { JClass::from_raw(class2) }; + + let service = env.new_string(auth_options.service)?; + let title = env.new_string(auth_options.title)?; + let subtitle = env.new_string(auth_options.subtitle)?; + let description = env.new_string(auth_options.description)?; + let cancel = env.new_string(auth_options.cancel)?; + let accessible = env.new_string(auth_options.accessible)?; + //let storage = env.new_string(auth_options.storage?)?; + let security_level = env.new_string(auth_options.securityLevel)?; + // let authentication_type = env.new_string(auth_options.authenticationType?)?; + + let mut access_control = JObject::from(env.new_string("None")?); + + if auth_type.as_str() == "true" { + access_control = JObject::from(env.new_string("BiometryCurrentSet")?); + } + + let mut storage = JObject::from(env.new_string("KeystoreRSAECB")?); + let sto = auth_options.storage; + + if let Some(s) = sto { + storage = JObject::from(env.new_string(s)?); + } + + let mut authentication_type = JObject::null(); + let aut = auth_options.authenticationType; + + if let Some(a) = aut { + authentication_type = JObject::from(env.new_string(a)?); + } + + let jservice = JValue::Object(&service); + let jtitle = JValue::Object(&title); + let jsubtitle = JValue::Object(&subtitle); + let jdescription = JValue::Object(&description); + let jcancel = JValue::Object(&cancel); + let jaccessible = JValue::Object(&accessible); + let jaccess_control = JValue::Object(&access_control); + let jstorage = JValue::Object(&storage); + let jsecurity_level = JValue::Object(&security_level); + let jauthentication_type = JValue::Object(&authentication_type); + + let result = env.call_static_method(class, "constructOptions", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/util/Map;", + &[jservice, jtitle, jsubtitle, jdescription, jcancel, jaccessible, jaccess_control, jstorage, jsecurity_level, jauthentication_type])?; + + let exceptions = env.exception_occurred()?; + + if exceptions.is_null() { + println!("No exception occurred for options"); + } else { + println!("Exception occurred for options"); + env.exception_describe()?; + env.exception_clear()?; + } + + let options = result.l()?; + let jkey_type = env.new_string(key_type.to_string())?; + let alias = env.new_string("AV_KEYSTORE")?; + let context = unsafe { JObject::from_raw(activity as jni::sys::jobject) }; + + let auth = match auth_type.as_str() { + "true" => true, + "false" => false, + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error getting auth type".to_string(), + "Error getting auth type".to_string(), + )) + } + }; + + print!("Before failure"); + let key = Java_com_example_keystore_KeyStoreModule_get( + env, class2, alias, options, context, jkey_type, + )?; + + let key = match auth { + true => match key_type { + "avl-p" => { + let wallet = AvailWallet::::from_bytes(&key)?; + Keys::PrivateKey(wallet.private_key) + } + "avl-v" => { + let view_key = ViewKey::::from_bytes_le(&key)?; + Keys::ViewKey(view_key) + } + _ => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Invalid key type".to_string(), + "Invalid key type".to_string(), + )) + } + }, + false => { + let password = password.ok_or(AvailError::new( + AvailErrorType::Internal, + "Login".to_string(), + "Login".to_string(), + ))?; + match key_type { + "avl-p" => { + let pkey_ciphertext = Ciphertext::::from_bytes_le(&key)?; + let pkey = Encryptor::::decrypt_private_key_with_secret( + &pkey_ciphertext, + password, + )?; + + Keys::PrivateKey(pkey) + } + "avl-v" => { + let vkey_ciphertext = Ciphertext::::from_bytes_le(&key)?; + let vkey = + Encryptor::::decrypt_view_key_with_secret(&vkey_ciphertext, password)?; + + Keys::ViewKey(vkey) + } + _ => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Invalid key type".to_string(), + "Invalid key type".to_string(), + )) + } + } + } + }; + + Ok(key) +} + +///Deletes the data stored in SharedPreferences and the key in keystore. +#[tauri::command(rename_all = "snake_case")] +pub fn keystore_delete(password: Option<&str>) -> AvailResult { + let network = get_network()?; + + let _validation = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => keystore_load::(password, "avl-v")?, + }; + + let (jvm, activity) = prepare_jvm()?; + + let _env = jvm.attach_current_thread()?; + + let mut env = jvm.get_env()?; + + let class = env.find_class("com/example/keystore/KeyStoreModule")?; + + let alias = env.new_string("AV_KEYSTORE")?; + let context = unsafe { JObject::from_raw(activity as jni::sys::jobject) }; + + Java_com_example_keystore_KeyStoreModule_delete(env, class, alias, context)?; + + delete_user_encrypted_data()?; + delete_user()?; + delete_all_server_storage()?; + remove_view_session()?; + delete_user_preferences()?; + + Ok("Keystore Deleted".to_string()) +} + +/// Checks if the device supports biometric authentication using jni +#[tauri::command(rename_all = "snake_case")] +pub fn device_auth_availability() -> AvailResult { + let (jvm, activity) = prepare_jvm()?; + + jvm.attach_current_thread()?; + + let mut env = jvm.get_env()?; + + let class = env.find_class("com/example/keystore/KeyStoreModule")?; + + let context = unsafe { JObject::from_raw(activity as jni::sys::jobject) }; + + Java_com_example_keystore_KeyStoreModule_check(env, class, context) +} + +/// Checks if the app has permission to use biometric authentication +#[tauri::command(rename_all = "snake_case")] +pub fn device_auth_permission() -> AvailResult { + let (jvm, activity) = prepare_jvm()?; + + jvm.attach_current_thread()?; + + let mut env = jvm.get_env()?; + + let class = env.find_class("com/example/keystore/KeyStoreModule")?; + + let context = unsafe { JObject::from_raw(activity as jni::sys::jobject) }; + + Java_com_example_keystore_KeyStoreModule_permission(env, class, context) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::models::wallet::AvailWallet; + use avail_common::models::constants::STRONG_PASSWORD; + + #[test] + fn test_keystore_init_password() { + let wallet = AvailWallet::::new().unwrap(); + + let _result = keystore_init( + STRONG_PASSWORD, + false, + &wallet.private_key, + &wallet.view_key, + ) + .unwrap(); + } + + //Requires android environment to run + #[test] + fn test_keystore_init_biometric() { + let wallet = AvailWallet::::new().unwrap(); + + let _result = keystore_init("", true, &wallet.private_key, &wallet.view_key).unwrap(); + } + + //Requires android environment to run if not password auth + #[test] + fn test_keystore_load() { + let _result = keystore_load::(Some(STRONG_PASSWORD), "avl-p").unwrap(); + } + + //Requires android environment to run + #[test] + fn test_keystore_delete() { + let _result = keystore_delete(Some(STRONG_PASSWORD)).unwrap(); + } + + #[test] + fn test_delete_wallet() { + use crate::models::storage::persistent::PersistentStorage; + let storage = PersistentStorage::new().unwrap(); + storage.execute_query("DROP TABLE wallet").unwrap(); + } + + #[test] + fn test_vk_from_bytes() { + let v_key = [ + 208, 66, 183, 166, 111, 221, 124, 205, 251, 28, 154, 84, 205, 85, 179, 53, 10, 216, + 154, 110, 70, 94, 148, 38, 231, 248, 224, 159, 244, 81, 0, 0, + ]; + + let _hashkey = [ + 87, 43, 111, 89, 49, 111, 82, 90, 55, 120, 119, 78, 52, 82, 98, 69, 97, 55, 74, 84, + 110, 76, 116, 67, 76, 82, 82, 82, 116, 100, 115, 69, + ]; + + let _view_key = ViewKey::::from_bytes_le(&v_key).unwrap(); + } +} diff --git a/src-tauri/src/services/account/key_management/desktop.rs b/src-tauri/src/services/account/key_management/desktop.rs new file mode 100644 index 00000000..bdeaaf3a --- /dev/null +++ b/src-tauri/src/services/account/key_management/desktop.rs @@ -0,0 +1,229 @@ +use bip39::Mnemonic; +use keyring::Entry; +use snarkvm::console::program::{FromFields, Itertools, ToFields}; +use snarkvm::prelude::{ + Ciphertext, Field, FromStr, Literal, Network, Plaintext, PrivateKey, StringType, ViewKey, +}; + +use crate::{ + helpers::validation::validate_secret_password, + models::wallet::BetterAvailWallet, + services::local_storage::utils::{ + encrypt_private_key_with_password, encrypt_view_key_with_password, + }, +}; + +use crate::models::storage::encryption::{Keys, Keys::PrivateKey as PKey, Keys::ViewKey as VKey}; +use avail_common::{ + aleo_tools::encryptor::Encryptor, + errors::{AvailError, AvailErrorType, AvailResult}, +}; + +fn encrypt_seed_phrase_with_password( + password: &str, + seed_phrase: &str, +) -> AvailResult> { + let pass_field = Field::::new_domain_separator(password); + + let seed_phrase = Plaintext::::Literal( + Literal::String(StringType::::new(seed_phrase)), + once_cell::sync::OnceCell::new(), + ); + + let cipher = seed_phrase.encrypt_symmetric(pass_field)?; + + Ok(cipher) +} + +fn decrypt_seed_phrase_with_password( + ciphertext: Ciphertext, + password: &str, +) -> AvailResult { + let pass_field = Field::::new_domain_separator(password); + let seed_phrase = ciphertext.decrypt_symmetric(pass_field)?; + + //the seed phrase string currently looks like "\"light soon prepare wire blade charge female stage ridge happy pony chief\"" + // but needs to be "light soon prepare wire blade charge female stage ridge happy pony chief" + let seed_phrase = seed_phrase.to_string().replace("\"", ""); + + Ok(seed_phrase) +} + +pub fn store(wallet: &BetterAvailWallet, password: &str) -> AvailResult { + //encrypt keys with password + if validate_secret_password(password).is_err() { + return Err(AvailError::new( + AvailErrorType::Validation, + "Invalid password".to_string(), + "Invalid password".to_string(), + )); + } + + let ciphertext_p = encrypt_private_key_with_password::(password, &wallet.private_key)?; + + let ciphertext_v = encrypt_view_key_with_password::(password, &wallet.view_key)?; + + if let Some(mnemonic) = &wallet.mnemonic { + let ciphertext_seed = encrypt_seed_phrase_with_password::(password, mnemonic.phrase())?; + //seed-phrase storage + let s_entry = Entry::new("com.avail.wallet.phrase", "avl-s")?; + let encrypted_seed_phrase = ciphertext_seed.to_string(); + s_entry.set_password(&encrypted_seed_phrase)?; + } + + //private-key storage + let p_entry = Entry::new("com.avail.wallet.p", "avl-p")?; + let encrypted_private_key = ciphertext_p.to_string(); + p_entry.set_password(&encrypted_private_key)?; + + //view-key storage + let v_entry = Entry::new("com.avail.wallet.v", "avl-v")?; + let encrypted_viewing_key = ciphertext_v.to_string(); + v_entry.set_password(&encrypted_viewing_key)?; + + Ok("Key Stored".to_string()) +} + +pub fn read_key(password: &str, key_type: &str) -> AvailResult> { + let entry = match key_type { + "avl-p" => Entry::new("com.avail.wallet.p", key_type)?, + "avl-v" => Entry::new("com.avail.wallet.v", key_type)?, + _ => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Invalid Key Type".to_string(), + "Invalid Key Type".to_string(), + )) + } + }; + let key = entry.get_password()?; + + match key_type { + "avl-p" => { + let pkey_ciphertext = Ciphertext::::from_str(&key)?; + let pkey = Encryptor::::decrypt_private_key_with_secret(&pkey_ciphertext, password)?; + + Ok(Keys::PrivateKey(pkey)) + } + "avl-v" => { + let vkey_ciphertext = Ciphertext::::from_str(&key)?; + let vkey = Encryptor::::decrypt_view_key_with_secret(&vkey_ciphertext, password)?; + + Ok(Keys::ViewKey(vkey)) + } + _ => Err(AvailError::new( + AvailErrorType::InvalidData, + "Invalid label".to_string(), + "Invalid label".to_string(), + )), + } +} + +pub fn read_seed_phrase(password: &str) -> AvailResult { + let entry = Entry::new("com.avail.wallet.phrase", "avl-s")?; + let seed_phrase = entry.get_password()?; + + let seed_phrase_ciphertext = Ciphertext::::from_str(&seed_phrase)?; + let seed_phrase = decrypt_seed_phrase_with_password::(seed_phrase_ciphertext, password)?; + + Ok(seed_phrase) +} + +pub fn delete_key(password: &str) -> AvailResult { + // verify password is correct before deletion + read_key::(password, "avl-v")?; + + let p_entry = Entry::new("com.avail.wallet.p", "avl-p")?; + p_entry.delete_password()?; + + let v_entry = Entry::new("com.avail.wallet.v", "avl-v")?; + v_entry.delete_password()?; + + Ok("Key Deleted".to_string()) +} + +#[cfg(test)] +mod windows_linux_key_management_tests { + use super::*; + use rand::thread_rng; + use snarkvm::console::network::Testnet3; + + use avail_common::models::constants::{STRONG_PASSWORD, WEAK_PASSWORD}; + + #[test] + fn test_store_strong_password() { + let mut rng = thread_rng(); + let p_key = PrivateKey::::new(&mut rng).unwrap(); + let v_key = ViewKey::::try_from(&p_key).unwrap(); + + let avail_wallet = BetterAvailWallet::::try_from(p_key).unwrap(); + + store::(&avail_wallet, STRONG_PASSWORD).unwrap(); + } + + #[test] + fn test_store_weak_password() { + let mut rng = thread_rng(); + let p_key = PrivateKey::::new(&mut rng).unwrap(); + let v_key = ViewKey::::try_from(&p_key).unwrap(); + let avail_wallet = BetterAvailWallet::::try_from(p_key.to_string()).unwrap(); + let access_type = true; + + store::(&avail_wallet, WEAK_PASSWORD).unwrap(); + } + + #[test] + fn read_key_test() { + let mut rng = thread_rng(); + let p_key = PrivateKey::::new(&mut rng).unwrap(); + let v_key = ViewKey::::try_from(&p_key).unwrap(); + let avail_wallet = BetterAvailWallet::::try_from(p_key.to_string()).unwrap(); + println!("Original Private Key: {:?}", p_key); + println!("Original Viewing Key: {:?}", v_key); + + store::(&avail_wallet, STRONG_PASSWORD).unwrap(); + + let read_p_key = read_key::(STRONG_PASSWORD, "avl-p") + .unwrap() + .is_private_key() + .unwrap(); + let read_v_key = read_key::(STRONG_PASSWORD, "avl-v") + .unwrap() + .is_view_key() + .unwrap(); + + delete_key::(STRONG_PASSWORD).unwrap(); + + println!("Fetched Private Key: {:?}", read_p_key); + println!("Fetched Viewing Key: {:?}", read_v_key); + + assert_eq!(p_key, read_p_key); + assert_eq!(v_key, read_v_key); + } + + #[test] + fn delete_key_test() { + let mut rng = thread_rng(); + let p_key = PrivateKey::::new(&mut rng).unwrap(); + let v_key = ViewKey::::try_from(&p_key).unwrap(); + let avail_wallet = BetterAvailWallet::::try_from(p_key.to_string()).unwrap(); + + store::(&avail_wallet, STRONG_PASSWORD).unwrap(); + + delete_key::(STRONG_PASSWORD).unwrap(); + } + + #[test] + fn test_encrypt_seed_phrase_with_password() { + let seed_phrase = + "light soon prepare wire blade charge female stage ridge happy pony chief"; + let password = "password"; + + let ciphertext = + encrypt_seed_phrase_with_password::(password, seed_phrase).unwrap(); + let decrypted_seed_phrase = + decrypt_seed_phrase_with_password::(ciphertext, password).unwrap(); + + assert_eq!(seed_phrase, decrypted_seed_phrase); + } +} diff --git a/src-tauri/src/services/account/key_management/iOS.rs b/src-tauri/src/services/account/key_management/iOS.rs new file mode 100644 index 00000000..7f719a7b --- /dev/null +++ b/src-tauri/src/services/account/key_management/iOS.rs @@ -0,0 +1,244 @@ +use snarkvm::prelude::*; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use tid::{LAContext, LAPolicy}; + +#[cfg(any(target_os = "macos", target_os = "ios"))] +use security_framework::passwords::{self}; + +use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; + +///Accepts a private key and attempts to store it on the user's iOS device. +///Using apple's security framework we set access controls to protect the key entry. +///If biometrics are available we only add the SecAccessControl to the query. +#[cfg(any(target_os = "ios"))] +pub fn store_key_local( + key: &[u8], + password: &str, + access_type: bool, + key_type: bool, +) -> AvailResult<()> { + //check if user has biometry enabled + let mut ctx = LAContext::new(); + + let label = match key_type { + true => "avl-p", + false => "avl-v", + }; + + let account = match key_type { + true => "avail-user-private", + false => "avail-user-view", + }; + + let mut options = passwords_options::PasswordOptions::new_generic_password( + "com.avail.wallet", + account, + label, + ); + + let auth_control; + + if access_type { + //Change to BIOMETRY_CURRENT_SET (so new biometric sigs don't pass auth) + auth_control = passwords_options::AccessControlOptions::BIOMETRY_ANY; + } else { + auth_control = passwords_options::AccessControlOptions::APPLICATION_PASSWORD; + + ctx.set_credential(password); + + options.query.push(( + unsafe { CFString::wrap_under_get_rule(kSecUseAuthenticationContext) }, + unsafe { CFType::wrap_under_create_rule(ctx.into_ref()) }, + )); + } + + options.set_access_control_options(auth_control); + + passwords::set_password_internal(&mut options, key)?; + + Ok(()) +} + +/// stores both the private key and viewing key inside the keychain +#[cfg(any(target_os = "ios"))] +pub fn store_keys_local( + password: &str, + access_type: bool, + p_key: &PrivateKey, + v_key: &ViewKey, +) -> AvailResult { + store_key_local(&p_key.to_bytes_le()?, password, access_type, true)?; + store_key_local(&v_key.to_bytes_le()?, password, access_type, false)?; + + Ok("Key Stored".to_string()) +} + +#[cfg(any(target_os = "ios"))] +/// Accepts user's password if using applicaiton password to authenticate +/// We construct a CFDictionary query to search for the key entry in the keychain. +/// using SecItemCopyMatching we attempt to retrieve the key entry from the keychain. +/// and pass in the context to SecItemCopyMatching. +/// If using biometrics we just pass in the SecAccessControl to the query but then this is blocking (seperate method). +pub fn search(password: Option<&str>, label: &str) -> AvailResult> { + let auth = get_auth_type()?; + + let account = try_label_to_account_str(label)?; + + let context = if auth { + None + } else { + password.map(|password| { + let mut ctx = LAContext::new(); + ctx.set_credential(password); + ctx.into_ref() as *const libc::c_void + }) + }; + + let key = get_generic_password("com.avail", &account, auth, context, label)?; + + match label { + "avl-p" => { + let wallet = AvailWallet::::from_bytes(&key)?; + + Ok(Keys::PrivateKey(wallet.private_key)) + } + "avl-v" => { + let viewing_key = ViewKey::::from_bytes_le(&key)?; + + Ok(Keys::ViewKey(viewing_key)) + } + _ => Err(AvailError::new( + AvailErrorType::InvalidData, + "Invalid label".to_string(), + "Invalid label".to_string(), + )), + } +} + +/* --Production-- */ +/* +#[cfg(any(target_os = "macos", target_os = "ios"))] +#[tauri::command(rename_all = "snake_case")] +pub fn delete_ios(password: Option<&str>) -> AvailResult { + let network = get_network()?; + // verify password is correct before deletion + let _validation = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => search::(password, "avl-v")?, + }; + + match passwords::delete_generic_password("com.avail", "avail-user-view", "avl-v") { + Ok(_) => (), + Err(e) => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Viewing key not found locally".to_string(), + format!("{:?}", e), + )) + } + }; + + match passwords::delete_generic_password("com.avail", "avail-user-private", "avl-p") { + Ok(_) => (), + Err(e) => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Private key not found locally".to_string(), + format!("{:?}", e), + )) + } + }; + + delete_user_encrypted_data()?; + delete_user()?; + delete_all_server_storage()?; + remove_view_session()?; + delete_user_preferences()?; + + Ok("Wallet Deleted".to_string()) +} +*/ + +// TODO - This should only delete key, user deletion should be a separate function call +/* --Testing-- */ +#[tauri::command(rename_all = "snake_case")] +pub async fn delete_ios(_password: Option<&str>) -> AvailResult { + match passwords::delete_generic_password("com.avail", "avail-user-view", "avl-v") { + Ok(_) => (), + Err(e) => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Viewing key not found locally".to_string(), + format!("{:?}", e), + )) + } + }; + + match passwords::delete_generic_password("com.avail", "avail-user-private", "avl-p") { + Ok(_) => (), + Err(e) => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Private key not found locally".to_string(), + format!("{:?}", e), + )) + } + }; + Ok("Key Deleted".to_string()) +} + +/// Checks if the user's device has biometrics enabled. +#[tauri::command(rename_all = "snake_case")] +#[cfg(any(target_os = "macos", target_os = "ios"))] +pub fn prepare_context() -> bool { + let ctx = LAContext::new(); + ctx.can_evaluate_policy(LAPolicy::DeviceOwnerAuthenticationWithBiometrics) +} + +#[cfg(any(target_os = "ios"))] +//issues with entitlement signing on mac (see way to run all tests for mac with entitlement added) +#[cfg(test)] +mod tests { + use super::*; + use avail_common::models::constants::STRONG_PASSWORD; + use snarkvm::prelude::{PrivateKey, Testnet3}; + + #[test] + fn test_store_key_local_password() { + let pk = PrivateKey::::new(&mut rand::thread_rng()).unwrap(); + let seed = pk.to_bytes_le().unwrap(); + let password = STRONG_PASSWORD.to_string(); + + store_key_local(&seed, &password, false, true).unwrap(); + } + + #[test] + fn test_store_key_local_biometrics() { + let pk = PrivateKey::::new(&mut rand::thread_rng()).unwrap(); + let seed = pk.to_bytes_le().unwrap(); + + store_key_local(&seed, "", true, true).unwrap(); + } + + #[test] + fn test_context_set_credential() { + let mut ctx = LAContext::new(); + ctx.set_credential(STRONG_PASSWORD); + + let _cf = unsafe { CFType::wrap_under_get_rule(ctx.into_ref()) }; + } + + #[test] + fn test_search_password() { + search::(Some(STRONG_PASSWORD), "avl-p").unwrap(); + } + + #[test] + fn test_search_biometrics() { + search::(None, "avl-p").unwrap(); + } + + #[tokio::test] + async fn delete_key() { + delete_ios(None).await.unwrap(); + } +} diff --git a/src-tauri/src/services/account/key_management/key_controller.rs b/src-tauri/src/services/account/key_management/key_controller.rs new file mode 100644 index 00000000..b485205d --- /dev/null +++ b/src-tauri/src/services/account/key_management/key_controller.rs @@ -0,0 +1,207 @@ +use crate::models::{storage::encryption::Keys, wallet::BetterAvailWallet}; +use crate::services::local_storage::session::password::PASS; + +#[cfg(target_os = "android")] +use super::android::{keystore_delete, keystore_init, keystore_load}; + +#[cfg(any(target_os = "ios"))] +use super::ios::{delete_ios, search, store_keys_local}; + +use snarkvm::prelude::{Identifier, Network, PrivateKey, ViewKey}; + +use super::desktop::{delete_key, read_key, read_seed_phrase, store}; +use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; + +/// This trait is used as a standard interface for the key management service. +/// The key_type field refers to the private key type when true and the viewing key type when false. +pub trait KeyController { + fn store_key(&self, password: &str, wallet: &BetterAvailWallet) -> AvailResult; + + fn delete_key(&self, password: Option<&str>, ext: Identifier) -> AvailResult; + fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult>; + fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult; +} + +pub struct AndroidKeyController; + +#[cfg(target_os = "android")] +impl KeyController for AndroidKeyController { + fn store_key(&self, password: &str, wallet: BetterAvailWallet) -> AvailResult { + keystore_init(password, access_type, p_key, v_key) + } + + fn import_key( + &self, + password: &str, + p_key: &PrivateKey, + v_key: &ViewKey, + ) -> AvailResult { + keystore_init(password, access_type, p_key, v_key) + } + + //TODO authenticate using read_key + fn delete_key(&self, password: Option<&str>, ext: Identifier) -> AvailResult { + keystore_delete(password) + } + + fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult> { + keystore_load(password, key_type) + } + + fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult { + read_seed_phrase::(password) + } +} + +pub struct iOSKeyController; + +#[cfg(target_os = "ios")] +impl KeyController for iOSKeyController { + fn store_key(&self, password: &str, wallet: BetterAvailWallet) -> AvailResult { + store_keys_local(password, access_type, p_key, v_key) + } + + fn import_key( + &self, + password: &str, + access_type: bool, + p_key: &PrivateKey, + v_key: &ViewKey, + ) -> AvailResult { + store_keys_local(password, access_type, p_key, v_key) + } + + //TODO authenticate using read_key + fn delete_key(&self, password: Option<&str>, ext: Identifier) -> AvailResult { + delete_ios(password) + } + + fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult> { + search(password, key_type) + } + + fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult { + read_seed_phrase(password, ext) + } +} + +pub struct macKeyController; + +#[cfg(target_os = "macos")] +impl KeyController for macKeyController { + fn store_key(&self, password: &str, wallet: &BetterAvailWallet) -> AvailResult { + store(wallet, password) + } + + fn delete_key(&self, password: Option<&str>, _ext: Identifier) -> AvailResult { + match password { + Some(password) => delete_key::(password), + None => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Password is required".to_string(), + "Password is required".to_string(), + )) + } + } + } + + fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult> { + match password { + Some(password) => read_key(password, key_type), + None => { + let password = match PASS.get_instance() { + Ok(password) => password, + Err(e) => return Err(e), + }; + + read_key(&password, key_type) + } + } + } + + fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult { + read_seed_phrase::(password) + } +} + +pub struct linuxKeyController; + +impl KeyController for linuxKeyController { + fn store_key(&self, password: &str, wallet: &BetterAvailWallet) -> AvailResult { + store(wallet, password) + } + + //TODO authenticate using read_key + fn delete_key(&self, password: Option<&str>, _ext: Identifier) -> AvailResult { + match password { + Some(password) => delete_key::(password), + None => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Password is required".to_string(), + "Password is required".to_string(), + )) + } + } + } + + fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult> { + match password { + Some(password) => read_key(password, key_type), + None => { + let password = match PASS.get_instance() { + Ok(password) => password, + Err(e) => return Err(e), + }; + + read_key(&password, key_type) + } + } + } + + fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult { + read_seed_phrase::(password) + } +} + +pub struct windowsKeyController; + +#[cfg(target_os = "windows")] +impl KeyController for windowsKeyController { + fn store_key(&self, password: &str, wallet: &BetterAvailWallet) -> AvailResult { + store(wallet, password) + } + + //TODO authenticate using read_key + fn delete_key(&self, password: Option<&str>, ext: Identifier) -> AvailResult { + match password { + Some(password) => delete_key::(password), + None => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Password is required".to_string(), + "Password is required".to_string(), + )) + } + } + } + + fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult> { + match password { + Some(password) => read_key(password, key_type), + None => { + let password = match PASS.get_instance() { + Ok(password) => password, + Err(e) => return Err(e), + }; + + read_key(&password, key_type) + } + } + } + + fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult { + read_seed_phrase::(password) + } +} diff --git a/src-tauri/src/services/account/phrase_recovery.rs b/src-tauri/src/services/account/phrase_recovery.rs new file mode 100644 index 00000000..29b54b4d --- /dev/null +++ b/src-tauri/src/services/account/phrase_recovery.rs @@ -0,0 +1,96 @@ +use snarkvm::prelude::{Testnet3, ToBytes}; + +use crate::{ + models::storage::languages::Languages, + services::local_storage::{ + encrypted_data::initialize_encrypted_data_table, + persistent_storage::initial_user_preferences, session::view::VIEWSESSION, + }, +}; + +use avail_common::errors::AvailResult; + +use crate::api::user::{create_user, get_user}; +use crate::models::wallet::BetterAvailWallet; +use crate::services::account::key_management::key_controller::{ + linuxKeyController, macKeyController, windowsKeyController, KeyController, +}; +use crate::services::authentication::session::get_session_after_creation; +use crate::services::local_storage::{ + encrypted_data::get_and_store_all_data, tokens::init_tokens_table, +}; +use avail_common::models::user::User; + +#[tauri::command(rename_all = "snake_case")] +/// This function provides the tauri bindings to recover an avail wallet from a seed phrase. +pub async fn recover_wallet_from_seed_phrase( + seed_phrase: &str, + password: &str, + access_type: bool, + language: Languages, +) -> AvailResult<()> { + let avail_wallet = BetterAvailWallet::::from_seed_phrase( + seed_phrase, + Languages::to_bip39_language(&language), + )?; + + let key_manager = { + #[cfg(target_os = "macos")] + { + macKeyController + } + #[cfg(target_os = "windows")] + { + windowsKeyController + } + #[cfg(target_os = "linux")] + { + linuxKeyController + } + }; + + key_manager.store_key(password, &avail_wallet)?; + + get_session_after_creation::(&avail_wallet.private_key).await?; + + let (username, tag, backup) = match get_user().await { + Ok(user) => (user.username, user.tag, user.backup), + Err(_) => { + let request = User { + username: None, + address: avail_wallet.get_address(), + tag: None, + backup: false, + }; + create_user(request).await?; + (None, None, false) + } + }; + + let _v_key = avail_wallet.view_key.to_bytes_le()?; + + initial_user_preferences( + access_type, + username, + tag, + true, + backup, + avail_wallet.get_address(), + language, + )?; + + init_tokens_table()?; + + // some function + + initialize_encrypted_data_table()?; + VIEWSESSION + .set_view_session(&avail_wallet.get_view_key()) + .unwrap(); + + if backup { + get_and_store_all_data().await?; + } + + Ok(()) +} diff --git a/src-tauri/src/services/account/shard_recovery.rs b/src-tauri/src/services/account/shard_recovery.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src-tauri/src/services/account/shard_recovery.rs @@ -0,0 +1 @@ + diff --git a/src-tauri/src/services/account/utils.rs b/src-tauri/src/services/account/utils.rs new file mode 100644 index 00000000..8204c7c2 --- /dev/null +++ b/src-tauri/src/services/account/utils.rs @@ -0,0 +1,76 @@ +use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; +use rand::Rng; +use std::process::Command; + +pub fn generate_discriminant() -> u32 { + let mut rng = rand::thread_rng(); + let mut discriminant: u32 = 0; + for _ in 0..4 { + discriminant = discriminant * 10 + rng.gen_range(0..10); + } + discriminant +} + +#[tauri::command(rename_all = "snake_case")] +pub fn open_url(url: &str) -> AvailResult<()> { + #[cfg(target_os = "windows")] + match Command::new("cmd").args(&["/c", "start", url]).spawn() { + Ok(_) => return Ok(()), + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + format!("Error opening url: {}", e), + "Error opening url".to_string(), + )) + } + }; + + #[cfg(target_os = "macos")] + match Command::new("open").arg(url).spawn() { + Ok(_) => return Ok(()), + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + format!("Error opening url: {}", e), + "Error opening url".to_string(), + )) + } + }; + + #[cfg(target_os = "linux")] + match Command::new("xdg-open").arg(url).spawn() { + Ok(_) => return Ok(()), + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + format!("Error opening url: {}", e), + "Error opening url".to_string(), + )) + } + }; +} + +#[tauri::command(rename_all = "snake_case")] +pub fn os_type() -> AvailResult { + #[cfg(target_os = "windows")] + return Ok("windows".to_string()); + + #[cfg(target_os = "macos")] + return Ok("macos".to_string()); + + #[cfg(target_os = "linux")] + return Ok("linux".to_string()); +} + +#[test] +fn test_generate_discriminant() { + let discriminant = generate_discriminant(); + print!("discriminant: {}", discriminant); + assert!(discriminant > 999 && discriminant < 10000); +} + +#[test] +fn test_open_url() { + let result = open_url("https://discord.gg/A6N5X2yX"); + assert!(result.is_ok()); +} diff --git a/src-tauri/src/services/authentication.rs b/src-tauri/src/services/authentication.rs new file mode 100644 index 00000000..3c452ed3 --- /dev/null +++ b/src-tauri/src/services/authentication.rs @@ -0,0 +1,7 @@ +pub mod session; + +#[cfg(any(target_os = "ios"))] +pub mod ios; + +#[cfg(target_os = "android")] +pub mod android; diff --git a/src-tauri/src/services/authentication/android.rs b/src-tauri/src/services/authentication/android.rs new file mode 100644 index 00000000..799ec6c2 --- /dev/null +++ b/src-tauri/src/services/authentication/android.rs @@ -0,0 +1,39 @@ +use snarkvm::prelude::{Testnet3, ToBytes}; +use std::str::FromStr; + +use crate::{ + models::storage::encryption::Keys, + services::{ + account::key_management::android::keystore_load, + local_storage::persistent_storage::{get_network, store_view_session}, + }, +}; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::network::SupportedNetworks, +}; + +#[tauri::command(rename_all = "snake_case")] +pub fn android_auth(password: Option<&str>, _key_type: &str) -> AvailResult<()> { + let network = get_network()?; + + let result = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => keystore_load::(password, "avl-v")?, + }; + + let view_key_bytes = match result { + Keys::ViewKey(key) => key.to_bytes_le()?, + Keys::PrivateKey(_) => { + return Err(AvailError::new( + AvailErrorType::InvalidData, + "Invalid Key Type".to_string(), + "Invalid Key Type".to_string(), + )) + } + }; + + store_view_session(view_key_bytes)?; + + Ok(()) +} diff --git a/src-tauri/src/services/authentication/ios.rs b/src-tauri/src/services/authentication/ios.rs new file mode 100644 index 00000000..aa3cf432 --- /dev/null +++ b/src-tauri/src/services/authentication/ios.rs @@ -0,0 +1,37 @@ +use snarkvm::prelude::{Testnet3, ToBytes}; +use std::str::FromStr; + +use avail_common::models::network::SupportedNetworks; + +use crate::services::local_storage::{persistent_storage::get_network, session::view::VIEWSESSION}; + +#[cfg(any(target_os = "ios"))] +use crate::{models::storage::encryption::Keys, services::account::key_management::ios::search}; + +use avail_common::errors::{AvError, AvailErrorType, AvailResult}; + +#[cfg(any(target_os = "ios"))] +#[tauri::command(rename_all = "snake_case")] +pub fn ios_auth(password: Option<&str>, key_type: &str) -> AvailResult<()> { + let network = get_network()?; + + let key = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => search::(password, key_type)?, + _ => search::(password, key_type)?, + }; + + let view_key_bytes = match key { + Keys::ViewKey(key) => key.to_bytes_le()?, + _ => { + return Err(AvError::new( + AvailErrorType::InvalidData, + "Invalid Key Type".to_string(), + "Invalid Key Type".to_string(), + )) + } + }; + + //TODO - Store view key session + + Ok(()) +} diff --git a/src-tauri/src/services/authentication/session.rs b/src-tauri/src/services/authentication/session.rs new file mode 100644 index 00000000..0703580f --- /dev/null +++ b/src-tauri/src/services/authentication/session.rs @@ -0,0 +1,327 @@ +use crate::api::client::SESSION; +use crate::helpers::utils::HOST; +use crate::models::auth::{CreateSessionRequest, VerifySessionResponse}; +use crate::services::local_storage::{ + persistent_storage::{get_address_string, get_network}, + session::password::PASS, + utils::{sign_message, sign_message_w_key}, +}; +use snarkvm::prelude::*; +use tauri_plugin_http::reqwest; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::{ + network::SupportedNetworks, + server_auth::{self, VerifySessionRequest}, + }, +}; + +/// Authenticates user both locally and on server. +#[tauri::command(rename_all = "snake_case")] +pub async fn get_session(password: Option) -> AvailResult { + let address = get_address_string()?; + let session_request = request_hash(&address).await?; + + let network = get_network()?; + + let (sig, _) = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + sign_message::(&session_request.hash, password.clone())? + } + _ => sign_message::(&session_request.hash, password.clone())?, + }; + + let verify_request = server_auth::VerifySessionRequest { + signature: sig.to_string(), + session_id: session_request.session_id, + }; + + let api = env!("API"); + + let client = reqwest::Client::new(); + + let res = client + .post(format!("{}/auth/login/", api)) + .json(&verify_request) + .send() + .await?; + + if res.status() == 200 { + let cookie = res.cookies().next(); + + let session_cookie = match cookie { + Some(cookie) => cookie, + None => { + return Err(AvailError::new( + AvailErrorType::Validation, + "Session cookie not found in auth response".to_string(), + "Session cookie not found in auth response".to_string(), + )) + } + }; + + SESSION.set_session_token(session_cookie.value().to_string()); + + let _pass_session = match password { + Some(password) => PASS.set_pass_session(&password)?, + None => {} + }; + + Ok(session_request.session_id.to_string()) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Invalid Signature".to_string(), + "Invalid Signature".to_string(), + )) + } +} + +pub async fn get_session_after_creation( + private_key: &PrivateKey, +) -> AvailResult { + let address = Address::::try_from(private_key)?; + let session_request = request_hash(&address.to_string()).await?; + + let (sig, _) = sign_message_w_key::(&session_request.hash, private_key)?; + + let verify_request = server_auth::VerifySessionRequest { + signature: sig.to_string(), + session_id: session_request.session_id, + }; + + let api = env!("API"); + + let res = reqwest::Client::new() + .post(format!("{}/auth/login/", api)) + .json(&verify_request) + .send() + .await?; + + if res.status() == 200 { + let cookie = res.cookies().next(); + + let session_cookie = match cookie { + Some(cookie) => cookie, + None => { + return Err(AvailError::new( + AvailErrorType::Validation, + "Session cookie not found in auth response".to_string(), + "Session cookie not found in auth response".to_string(), + )) + } + }; + + SESSION.set_session_token(session_cookie.value().to_string()); + + Ok(session_request.session_id.to_string()) + } else { + if res.status() == 0 { + return Err(AvailError::new( + AvailErrorType::Network, + "No internet connection".to_string(), + "No internet connection".to_string(), + )); + } + + Err(AvailError::new( + AvailErrorType::External, + "Invalid Signature".to_string(), + "Invalid Signature".to_string(), + )) + } +} + +/// requests the initial hash to sign from server +/// Function 1 +pub async fn request_hash(address: &str) -> AvailResult { + let client = reqwest::Client::new(); + + let request = server_auth::CreateSessionRequest { + public_key: address.to_owned(), + }; + + let api = env!("API"); + + let res = client + .post(format!("{}/auth/request/", api)) + .header("Content-Type", "application/json") + .json(&request) + .send() + .await?; + + if res.status() == 201 { + Ok(res.json::().await?) + } else { + if res.status() == 0 { + return Err(AvailError::new( + AvailErrorType::Network, + "No internet connection".to_string(), + "No internet connection".to_string(), + )); + } + + Err(AvailError::new( + AvailErrorType::External, + "Error requesting auth token.".to_string(), + "Error requesting auth token.".to_string(), + )) + } +} + +/* -- Not used -- */ + +///Function 2 +pub fn sign_hash( + request: CreateSessionRequest, + password: Option, +) -> AvailResult { + let network = get_network()?; + + let (sig, _) = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => sign_message::(&request.hash, password)?, + _ => sign_message::(&request.hash, password)?, + }; + + let verify_request = server_auth::VerifySessionRequest { + signature: sig.to_string(), + session_id: request.to_response().session_id, + }; + + Ok(verify_request) +} + +///Function 3 +pub async fn get_session_only(request: VerifySessionResponse) -> AvailResult { + let client = reqwest::Client::new(); + + let res = client + .post("https://test-api.avail.global/auth/login/") + .json(&request.to_request()) + .send() + .await?; + + if res.status() == 200 { + res.json::().await?; + // store session id in local storage (cookies) + Ok(request.session_id.to_string()) + } else { + Err(AvailError::new( + AvailErrorType::External, + "Invalid Signature".to_string(), + "Invalid Signature".to_string(), + )) + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + use crate::api::encrypted_data::get_new_transaction_messages; + use crate::api::user::create_user; + use crate::models::storage::languages::Languages; + use crate::models::wallet::BetterAvailWallet; + use crate::services::account::key_management::desktop::{delete_key, store}; + use crate::services::account::utils::generate_discriminant; + use crate::services::local_storage::encrypted_data::delete_user_encrypted_data; + use crate::services::local_storage::persistent_storage::{ + delete_user_preferences, initial_user_preferences, + }; + use crate::services::local_storage::session::view::VIEWSESSION; + use avail_common::models::constants::{STRONG_PASSWORD, TESTNET_PRIVATE_KEY}; + use avail_common::models::user::User; + use snarkvm::prelude::Testnet3; + + use avail_common::converters::messages::{field_to_fields, utf8_string_to_bits}; + + #[tokio::test] + async fn test_setup_prerequisites() { + match delete_key::(STRONG_PASSWORD) { + Ok(_) => println!("Key Deleted"), + Err(_) => println!("No key found"), + } + + // delete_user().await.unwrap(); + delete_user_encrypted_data().unwrap(); + delete_user_preferences().unwrap(); + + let p_key = PrivateKey::::new(&mut rand::thread_rng()).unwrap(); + let wallet = BetterAvailWallet::::try_from(p_key.to_string()).unwrap(); + + let v_key = ViewKey::::try_from(&p_key).unwrap(); + + let tag = generate_discriminant(); + + initial_user_preferences( + false, + Some("Karp".to_string()), + Some(tag), + false, + false, + v_key.to_address().to_string(), + Languages::English, + ) + .unwrap(); + + VIEWSESSION.set_view_session(&v_key.to_string()).unwrap(); + + let user_request = User { + address: v_key.to_address().to_string(), + username: Some("Karp".to_string()), + tag: Some(tag), + backup: false, + }; + + create_user(user_request).await.unwrap(); + + store::(&wallet, STRONG_PASSWORD).unwrap(); + } + + #[tokio::test] + async fn test_get_session_password() { + //let username = get_username().unwrap(); + // test_setup_prerequisites(); + let session = get_session(Some(STRONG_PASSWORD.to_string())) + .await + .unwrap(); + print!("{}", session); + + get_new_transaction_messages::().await.unwrap(); + + println!("Successful fetch"); + + //let address =name_to_address::(&username).await.unwrap(); + //let user = get_user().await.unwrap(); + } + + #[tokio::test] + async fn test_request_hash() { + let address = get_address_string().unwrap(); + + let hash = request_hash(&address).await; + print!("{}", hash.unwrap().hash); + // assert!(hash.is_ok()); + } + + #[test] + fn test_sign_hash() { + let sig = { + let key = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + + //get private key from local storage + + let rng = &mut rand::thread_rng(); + + let msg = utf8_string_to_bits("KEqj6BDUl0Nh0izyOsXuW916qSoGxtfE"); + let msg_field = Testnet3::hash_bhp512(&msg).unwrap(); + let msg = field_to_fields(&msg_field).unwrap(); + + key.sign(&msg, rng).unwrap() + }; + + print!("{}", sig.to_string()); + } +} diff --git a/src-tauri/src/services/local_storage.rs b/src-tauri/src/services/local_storage.rs new file mode 100644 index 00000000..c23e04c0 --- /dev/null +++ b/src-tauri/src/services/local_storage.rs @@ -0,0 +1,6 @@ +pub mod encrypted_data; +pub mod persistent_storage; +pub mod session; +pub mod storage_api; +pub mod tokens; +pub mod utils; diff --git a/src-tauri/src/services/local_storage/encrypted_data.rs b/src-tauri/src/services/local_storage/encrypted_data.rs new file mode 100644 index 00000000..eb2f70fc --- /dev/null +++ b/src-tauri/src/services/local_storage/encrypted_data.rs @@ -0,0 +1,794 @@ +use std::str::FromStr; + +use chrono::{DateTime, Utc}; +use rusqlite::{params_from_iter, ToSql}; +use snarkvm::prelude::{Network, Testnet3}; + +use crate::models::pointers::{ + deployment::DeploymentPointer, record::AvailRecord, transaction::TransactionPointer, + transition::TransitionPointer, +}; +use crate::models::storage::persistent::PersistentStorage; +use crate::{ + api::encrypted_data::recover_data, + services::local_storage::{persistent_storage::*, session::view::VIEWSESSION}, +}; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::encrypted_data::{ + EncryptedData, EncryptedDataTypeCommon, EventTypeCommon, RecordTypeCommon, TransactionState, + }, + models::network::SupportedNetworks, +}; + +/* Main Encrypted Data funcions */ + +///initialize enrypted data table +pub fn initialize_encrypted_data_table() -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + storage.execute_query( + "CREATE TABLE IF NOT EXISTS encrypted_data ( + id TEXT PRIMARY KEY, + owner TEXT NOT NULL, + ciphertext TEXT NOT NULL, + nonce TEXT NOT NULL, + flavour TEXT NOT NULL, + record_type TEXT, + program_ids TEXT, + function_ids TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP, + synced_on TIMESTAMP, + network TEXT NOT NULL, + record_name TEXT, + spent BOOLEAN, + event_type TEXT, + record_nonce TEXT, + state TEXT + )", + )?; + + Ok(()) +} + +/// store any encrypted data in persistent storage +pub fn store_encrypted_data(data: EncryptedData) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + let id = match data.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found.".to_string(), + "No id found.".to_string(), + ))?, + }; + + let flavour = data.flavour.to_str(); + let ciphertext = data.ciphertext; + let nonce = data.nonce; + let record_type = match data.record_type { + Some(record_type) => Some(record_type.to_str()), + None => None, + }; + let event_type = match data.event_type { + Some(event_type) => Some(event_type.to_str()), + None => None, + }; + let transaction_state = match data.transaction_state { + Some(transaction_state) => Some(transaction_state.to_str()), + None => None, + }; + + storage.save_mixed( + vec![&id,&data.owner, &ciphertext, &nonce, &flavour,&record_type,&data.program_ids,&data.function_ids,&data.created_at,&data.updated_at,&data.synced_on,&data.network,&data.record_name,&data.spent,&event_type,&data.record_nonce,&transaction_state], + "INSERT INTO encrypted_data (id,owner,ciphertext,nonce,flavour,record_type,program_ids,function_ids,created_at,updated_at,synced_on,network,record_name,spent,event_type,record_nonce,state) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17)" + .to_string(), + )?; + + Ok(()) +} + +pub fn handle_encrypted_data_query(query: &str) -> AvailResult> { + let storage = PersistentStorage::new()?; + + let mut query_statement = storage.conn.prepare(query)?; + + let query_iter = query_statement.query_map([], |row| { + let id: String = row.get(0)?; + let owner: String = row.get(1)?; + let ciphertext: String = row.get(2)?; + let nonce: String = row.get(3)?; + let flavour: String = row.get(4)?; + let record_type: Option = row.get(5)?; + let program_ids: Option = row.get(6)?; + let function_ids: Option = row.get(7)?; + let created_at: DateTime = row.get(8)?; + let updated_at: Option> = row.get(9)?; + let synced_on: Option> = row.get(10)?; + let network: String = row.get(11)?; + let record_name: Option = row.get(12)?; + let spent: Option = row.get(13)?; + let event_type: Option = row.get(14)?; + let record_nonce: Option = row.get(15)?; + let transaction_state: Option = row.get(16)?; + + let id = match uuid::Uuid::parse_str(&id) { + Ok(id) => id, + Err(_) => { + return Err(rusqlite::Error::InvalidColumnType( + 0, + "Error converting id string to uuid".to_string(), + rusqlite::types::Type::Text, + )) + } + }; + + let record_type = match record_type { + Some(record_type) => RecordTypeCommon::from_str(&record_type), + None => None, + }; + + let event_type = match event_type { + Some(event_type) => EventTypeCommon::from_str(&event_type), + None => None, + }; + + let transaction_state = match transaction_state { + Some(transaction_state) => TransactionState::from_str(&transaction_state), + None => None, + }; + + let flavour = EncryptedDataTypeCommon::from(flavour.as_str()); + + let encrypted_data = EncryptedData::new( + Some(id), + owner, + ciphertext, + nonce, + flavour, + record_type, + program_ids, + function_ids, + created_at, + updated_at, + synced_on, + network, + record_name, + spent, + event_type, + record_nonce, + transaction_state, + ); + + Ok(encrypted_data) + })?; + + let mut encrypted_data: Vec = Vec::new(); + + for data in query_iter { + encrypted_data.push(data?); + } + + Ok(encrypted_data) +} + +pub fn handle_encrypted_data_query_params( + query: &str, + query_params: Vec, +) -> AvailResult> { + let storage = PersistentStorage::new()?; + + let mut query_statement = storage.conn.prepare(query)?; + + let query_iter = query_statement.query_map(params_from_iter(query_params.iter()), |row| { + let id: String = row.get(0)?; + let owner: String = row.get(1)?; + let ciphertext: String = row.get(2)?; + let nonce: String = row.get(3)?; + let flavour: String = row.get(4)?; + let record_type: Option = row.get(5)?; + let program_ids: Option = row.get(6)?; + let function_ids: Option = row.get(7)?; + let created_at: DateTime = row.get(8)?; + let updated_at: Option> = row.get(9)?; + let synced_on: Option> = row.get(10)?; + let network: String = row.get(11)?; + let record_name: Option = row.get(12)?; + let spent: Option = row.get(13)?; + let event_type: Option = row.get(14)?; + let record_nonce: Option = row.get(15)?; + let transaction_state: Option = row.get(16)?; + + let id = match uuid::Uuid::parse_str(&id) { + Ok(id) => id, + Err(_) => { + return Err(rusqlite::Error::InvalidColumnType( + 0, + "Error converting id string to uuid".to_string(), + rusqlite::types::Type::Text, + )) + } + }; + + let record_type = match record_type { + Some(record_type) => RecordTypeCommon::from_str(&record_type), + None => None, + }; + + let event_type = match event_type { + Some(event_type) => EventTypeCommon::from_str(&event_type), + None => None, + }; + + let transaction_state = match transaction_state { + Some(transaction_state) => TransactionState::from_str(&transaction_state), + None => None, + }; + let flavour = EncryptedDataTypeCommon::from(flavour.as_str()); + + let encrypted_data = EncryptedData::new( + Some(id), + owner, + ciphertext, + nonce, + flavour, + record_type, + program_ids, + function_ids, + created_at, + updated_at, + synced_on, + network, + record_name, + spent, + event_type, + record_nonce, + transaction_state, + ); + + Ok(encrypted_data) + })?; + + let mut encrypted_data: Vec = Vec::new(); + + for data in query_iter { + encrypted_data.push(data?); + } + + Ok(encrypted_data) +} + +/// get encrypted data by their flavour +pub fn get_encrypted_data_by_flavour( + flavour: EncryptedDataTypeCommon, +) -> AvailResult> { + let address = get_address_string()?; + let network = get_network()?; + + let query = format!( + "SELECT * FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", + flavour.to_str(), + address, + network + ); + + handle_encrypted_data_query(&query) +} + +/// get encrypted data by id +pub fn get_encrypted_data_by_id(id: &str) -> AvailResult { + let query = format!("SELECT * FROM encrypted_data WHERE id='{}'", id); + + let encrypted_data = handle_encrypted_data_query(&query)?; + + if encrypted_data.len() > 0 { + Ok(encrypted_data[0].clone()) + } else { + Err(AvailError::new( + AvailErrorType::Internal, + "Data Not Found".to_string(), + "Data Not Found".to_string(), + )) + } +} + +/// get encrypted record pointer by nonce +pub fn get_encrypted_data_by_nonce(nonce: &str) -> AvailResult> { + let address = get_address_string()?; + let network = get_network()?; + + let query = format!( + "SELECT * FROM encrypted_data WHERE record_nonce='{}' AND owner='{}' AND network='{}'", + nonce, address, network + ); + + let encrypted_data = handle_encrypted_data_query(&query)?; + + if !encrypted_data.is_empty() { + Ok(Some(encrypted_data[0].clone())) + } else { + Ok(None) + } +} + +/* Main Encrypted Data funcions */ + +/// update encrypted data by id +pub fn update_encrypted_data_by_id(id: &str, ciphertext: &str, nonce: &str) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + let query = format!( + "UPDATE encrypted_data SET ciphertext=?1, nonce=?2 WHERE id='{}'", + id + ); + + storage.save_mixed(vec![&ciphertext, &nonce], query)?; + + Ok(()) +} + +/// update encrypted data by id +pub fn update_encrypted_data_spent_by_id( + id: &str, + ciphertext: &str, + nonce: &str, + spent: bool, +) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + let updated_at = Utc::now(); + + let query = format!( + "UPDATE encrypted_data SET ciphertext=?1, nonce=?2, spent=?3, updated_at=?4 WHERE id='{}'", + id + ); + + storage.save_mixed(vec![&ciphertext, &nonce, &spent, &updated_at], query)?; + + Ok(()) +} + +/// update encrypted data and transaction state by id +pub fn update_encrypted_transaction_state_by_id( + id: &str, + ciphertext: &str, + nonce: &str, + transaction_state: TransactionState, +) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + let query = format!( + "UPDATE encrypted_data SET ciphertext=?1, nonce=?2, state=?3 WHERE id='{}'", + id + ); + + storage.save_mixed( + vec![&ciphertext, &nonce, &transaction_state.to_str()], + query, + )?; + + Ok(()) +} + +/// update encrypted data by id and program_ids and function_ids +pub fn update_encrypted_transaction_confirmed_by_id( + id: &str, + ciphertext: &str, + nonce: &str, + program_ids: &str, + function_ids: &str, +) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + let query = format!( + "UPDATE encrypted_data SET ciphertext=?1, nonce=?2, program_ids=?3, function_ids=?4, state=?5 WHERE id='{}'", + id + ); + + storage.save_mixed( + vec![ + &ciphertext, + &nonce, + &program_ids, + &function_ids, + &TransactionState::Confirmed.to_str(), + ], + query, + )?; + + Ok(()) +} + +/// update synced_on field of encrypted data by id (data has been synced) +pub fn update_encrypted_data_synced_on_by_id(id: &str) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + let query = format!("UPDATE encrypted_data SET synced_on=?1 WHERE id='{}'", id); + + let synced_on = Utc::now(); + + storage.save_mixed(vec![&synced_on], query)?; + + Ok(()) +} + +/// delete encrypted data by id +pub fn delete_encrypted_data_by_id(id: &str) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + let query = format!("DELETE FROM encrypted_data WHERE id='{}'", id); + + storage.execute_query(&query)?; + + Ok(()) +} + +/// delete encrypted data by owner address +pub fn delete_encrypted_data_by_address() -> AvailResult<()> { + let storage = PersistentStorage::new()?; + let address = get_address_string()?; + + let query = format!("DELETE FROM encrypted_data WHERE owner='{}'", address); + + storage.execute_query(&query)?; + + Ok(()) +} + +/// delete user encrypted data storage +pub fn delete_user_encrypted_data() -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + let query = "DELETE FROM encrypted_data"; + + match storage.execute_query(query) { + Ok(r) => r, + Err(e) => match e.error_type { + AvailErrorType::NotFound => {} + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error deleting encrypted data ".to_string(), + "".to_string(), + )) + } + }, + }; + + Ok(()) +} + +pub fn drop_encrypted_data_table() -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + let query = "DROP TABLE encrypted_data"; + + match storage.execute_query(query) { + Ok(r) => r, + Err(e) => match e.error_type { + AvailErrorType::NotFound => {} + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error dropping encrypted data table ".to_string(), + "Error deleting encrypted data table".to_string(), + )) + } + }, + }; + + Ok(()) +} + +pub fn get_encrypted_data_to_backup( + last_backup_sync: DateTime, +) -> AvailResult> { + let query = "SELECT * FROM encrypted_data WHERE created_at > ?1"; + + let encrypted_data = handle_encrypted_data_query_params(query, vec![last_backup_sync])?; + + Ok(encrypted_data) +} + +pub fn get_encrypted_data_to_update( + last_backup_sync: DateTime, +) -> AvailResult> { + let query = "SELECT * FROM encrypted_data WHERE updated_at > ?1"; + + let encrypted_data = handle_encrypted_data_query_params(query, vec![last_backup_sync])?; + + Ok(encrypted_data) +} + +/// Function to handle the deletion of encrypted data when a scan fails at a specific block height +pub fn handle_block_scan_failure(block_height: u32) -> AvailResult<()> { + let view_key = VIEWSESSION.get_instance::()?; + + // get encrypted data stored withing the last two minutes + let query = "SELECT * FROM encrypted_data WHERE created_at > ?1"; + + let encrypted_data = handle_encrypted_data_query_params( + query, + vec![Utc::now() + .checked_sub_signed(chrono::Duration::minutes(2)) + .unwrap()], + )?; + + let mut ids_to_delete: Vec = vec![]; + + for data in encrypted_data { + let encrypted_struct = data.to_enrypted_struct::()?; + + match data.flavour { + EncryptedDataTypeCommon::Record => { + let record_pointer: AvailRecord = encrypted_struct.decrypt(view_key)?; + if record_pointer.pointer.block_height == block_height { + if let Some(id) = data.id { + ids_to_delete.push(id.to_string()); + } + } + } + EncryptedDataTypeCommon::Transaction => { + let tx_pointer: TransactionPointer = encrypted_struct.decrypt(view_key)?; + if let Some(tx_height) = tx_pointer.block_height() { + if tx_height == block_height { + ids_to_delete.push(data.id.unwrap().to_string()); + } + } + } + EncryptedDataTypeCommon::Deployment => { + let deployment: DeploymentPointer = encrypted_struct.decrypt(view_key)?; + + if let Some(deployment_height) = deployment.block_height { + if deployment_height == block_height { + ids_to_delete.push(data.id.unwrap().to_string()); + } + } + } + EncryptedDataTypeCommon::Transition => { + let transition: TransitionPointer = encrypted_struct.decrypt(view_key)?; + + if transition.block_height == block_height { + ids_to_delete.push(data.id.unwrap().to_string()); + } + } + _ => {} + } + } + + Ok(()) +} + +///get encrypted data and store directly locally encrypted +#[tauri::command(rename_all = "snake_case")] +pub async fn get_and_store_all_data() -> AvailResult { + let address = get_address_string()?; + let network = get_network()?; + + let data = recover_data(&address.to_string()).await?; + + for encrypted_record_pointer in data.record_pointers { + let e_r = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + AvailRecord::::to_encrypted_data_from_record(encrypted_record_pointer)? + } + _ => AvailRecord::::to_encrypted_data_from_record(encrypted_record_pointer)?, + }; + store_encrypted_data(e_r)?; + } + + for encrypted_transaction in data.transactions { + let e_t = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + TransactionPointer::::to_encrypted_data_from_record( + encrypted_transaction, + )? + } + _ => TransactionPointer::::to_encrypted_data_from_record( + encrypted_transaction, + )?, + }; + store_encrypted_data(e_t)?; + } + + for encrypted_deployment in data.deployments { + let e_t = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + DeploymentPointer::::to_encrypted_data_from_record(encrypted_deployment)? + } + _ => { + DeploymentPointer::::to_encrypted_data_from_record(encrypted_deployment)? + } + }; + store_encrypted_data(e_t)?; + } + + for encrypted_transition in data.transitions { + let e_t = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + TransitionPointer::::to_encrypted_data_from_record(encrypted_transition)? + } + _ => { + TransitionPointer::::to_encrypted_data_from_record(encrypted_transition)? + } + }; + store_encrypted_data(e_t)?; + } + + Ok("Data recovered and stored locally".to_string()) + + //now store the encoded/encrypted +} + +#[cfg(test)] +mod encrypted_data_tests { + use super::*; + use crate::api::encrypted_data::{delete_all_server_storage, post_encrypted_data}; + use std::str::FromStr; + + use crate::models::pointers::{ + record::AvailRecord, transaction::TransactionPointer, transition::TransitionPointer, + }; + use crate::models::storage::languages::Languages; + use crate::services::local_storage::persistent_storage::initial_user_preferences; + + use crate::services::local_storage::session::view::VIEWSESSION; + use crate::services::local_storage::storage_api::records::{ + encrypt_and_store_records, get_test_record_pointer, + }; + + use snarkvm::prelude::{PrivateKey, Testnet3, ToBytes, ViewKey}; + + use avail_common::models::constants::*; + + fn test_setup_prerequisites() { + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let view_key = ViewKey::::try_from(&pk).unwrap(); + + delete_user_encrypted_data().unwrap(); + + delete_user_preferences().unwrap(); + // initialize the user preferences + initial_user_preferences( + false, + None, + None, + false, + false, + view_key.to_address().to_string(), + Languages::English, + ) + .unwrap(); + initialize_encrypted_data_table().unwrap(); + + VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); + } + + #[test] + fn test_store_encrypted_data() { + test_setup_prerequisites(); + + let test_pointer = get_test_record_pointer(); + let address = get_address::().unwrap(); + + let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); + + println!("{:?}", encrypted_record); + // println!("{:?}", res); + } + + #[test] + fn test_get_encrypted_data_by_flavour() { + //test_store_encrypted_data(); + + VIEWSESSION + .set_view_session("AViewKey1myvhAr2nes8MF1y8gPV19azp4evwsBR4CqyzAi62nufW") + .unwrap(); + + let res = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record).unwrap(); + + let v_key = VIEWSESSION.get_instance::().unwrap(); + + let records = res + .iter() + .map(|x| { + let encrypted_data = x.to_enrypted_struct::().unwrap(); + let block: AvailRecord = encrypted_data.decrypt(v_key).unwrap(); + + block + }) + .collect::>>(); + + for record in records { + println!("{:?}\n", record); + } + } + + #[test] + fn test_get_encrypted_data_by_flavour_no_decrypt() { + let res = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record).unwrap(); + + for data in res { + println!("{:?}\n", data); + } + } + + #[test] + fn test_get_encrypted_data_by_id() { + test_setup_prerequisites(); + + let test_pointer = get_test_record_pointer(); + let address = get_address::().unwrap(); + + let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); + + let res = get_encrypted_data_by_id(&encrypted_record[0].id.unwrap().to_string()).unwrap(); + + println!("{:?}", res); + } + + #[test] + fn test_update_encrypted_data_by_id() { + test_setup_prerequisites(); + + let test_pointer = get_test_record_pointer(); + + let address = get_address::().unwrap(); + + let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); + + let res = update_encrypted_data_by_id( + &encrypted_record[0].id.unwrap().to_string(), + "ciphertext", + "nonce", + ); + + assert!(res.is_ok()); + } + + #[test] + fn test_delete_encrypted_data_by_id() { + test_setup_prerequisites(); + + let test_pointer = get_test_record_pointer(); + let address = get_address::().unwrap(); + + let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); + + let res = delete_encrypted_data_by_id(&encrypted_record[0].id.unwrap().to_string()); + assert!(res.is_ok()); + } + + #[test] + fn test_delete_user() { + delete_user_encrypted_data().unwrap(); + } + + #[test] + fn test_drop_encrypted_data() { + let storage = PersistentStorage::new().unwrap(); + + let query = "DROP TABLE encrypted_data"; + + storage.execute_query(query).unwrap(); + } + + #[tokio::test] + async fn test_get_and_store_all_data() { + test_setup_prerequisites(); + + let test_pointer = get_test_record_pointer(); + let address = get_address::().unwrap(); + + let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); + + post_encrypted_data(encrypted_record.clone()).await.unwrap(); + + let res = get_and_store_all_data().await.unwrap(); + println!("{:?}", res); + + delete_all_server_storage().await.unwrap(); + } +} diff --git a/src-tauri/src/services/local_storage/persistent_storage.rs b/src-tauri/src/services/local_storage/persistent_storage.rs new file mode 100644 index 00000000..3ba96b58 --- /dev/null +++ b/src-tauri/src/services/local_storage/persistent_storage.rs @@ -0,0 +1,489 @@ +use chrono::{DateTime, Utc}; +use snarkvm::prelude::*; + +use crate::models::{event::Network as EventNetwork, storage::languages::Languages}; +use crate::{ + api::aleo_client::{setup_client, setup_local_client}, + models::storage::persistent::PersistentStorage, +}; + +use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; + +///Definition: Initialises the user preferences table in persistent storage +pub fn initial_user_preferences( + auth_type: bool, + username: Option, + tag: Option, + import: bool, + backup: bool, + address: String, + language: Languages, +) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + let api_client = setup_client::().unwrap(); + + let latest_height = match import { + true => 0, + false => api_client.latest_height()?, + }; + + let last_tx_sync = Utc::now(); + + storage.execute_query( + "CREATE TABLE IF NOT EXISTS user_preferences ( + theme TEXT NOT NULL, + language TEXT NOT NULL, + network TEXT NOT NULL, + auth_type BOOLEAN NOT NULL DEFAULT FALSE, + username TEXT, + tag TEXT, + last_sync INTEGER NOT NULL, + last_tx_sync TIMESTAMP NOT NULL, + last_backup_sync TIMESTAMP, + backup BOOLEAN NOT NULL DEFAULT FALSE, + address TEXT NOT NULL + )", + )?; + + let username = match username { + Some(username) => username, + None => "".to_string(), + }; + + let tag = tag.unwrap_or(0); + + storage.save_mixed( + vec![ + &"dark", + &language.to_string_short(), + // TODO - V2 change default to mainnet + &"testnet3", + &auth_type, + &username, + &tag, + &latest_height, + &last_tx_sync, + &Some(Utc::now()), + &address, + &backup + ], + "INSERT INTO user_preferences (theme, language, network, auth_type, username, tag, last_sync, last_tx_sync, last_backup_sync, address, backup) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9,?10, ?11)".to_string(), + )?; + + Ok(()) +} + +///Deletes user preferences table from persistent storage -> This should be reset +#[tauri::command(rename_all = "snake_case")] +pub fn delete_user_preferences() -> AvailResult<()> { + let storage = PersistentStorage::new()?; + let query = "DROP TABLE user_preferences"; + + match storage.execute_query(query) { + Ok(r) => r, + Err(e) => match e.error_type { + AvailErrorType::NotFound => {} + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + e.internal_msg, + "Error deleting user preferences".to_string(), + )) + } + }, + }; + + Ok(()) +} + +///Switch authentication type between password and biometrics +pub fn change_auth_type() -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + let query = "SELECT auth_type FROM user_preferences".to_string(); + + let res = storage.get_all::(&query, 1)?; + + let auth_type = res[0][0]; + + let new_auth_type = !auth_type; + + storage.save( + vec![&new_auth_type], + "UPDATE user_preferences SET auth_type = ?1".to_string(), + )?; + + Ok(()) +} + +/// Get authentication type from user preferences +#[tauri::command(rename_all = "snake_case")] +pub fn get_auth_type() -> AvailResult { + let storage = PersistentStorage::new()?; + + let query = "SELECT auth_type FROM user_preferences".to_string(); + + let res = storage.get_all::(&query, 1)?; + + let auth_type = res[0][0].clone(); + + Ok(auth_type) +} + +///get username from user preferences +#[tauri::command(rename_all = "snake_case")] +pub fn get_username() -> AvailResult { + let storage = PersistentStorage::new()?; + + let query = "SELECT username || '#' || tag AS username_tag FROM user_preferences;".to_string(); + + let res = storage.get_all::(&query, 1)?; + + match res.get(0) { + Some(username) => { + if username[0] == "#0" { + return get_address_string(); + } else { + return Ok(username[0].clone()); + } + } + None => Err(AvailError::new( + AvailErrorType::LocalStorage, + "No username found".to_string(), + "No username found".to_string(), + )), + } +} + +pub fn update_username_local(username: &str, tag: i32) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + storage.save( + vec![Box::new(username.to_string()), Box::new(tag.to_string())], + "UPDATE user_preferences SET username = ?1, tag = ?2".to_string(), + )?; + + Ok(()) +} + +/// Get network from user preferences +#[tauri::command(rename_all = "snake_case")] +pub fn get_network() -> AvailResult { + let storage = PersistentStorage::new()?; + let query = "SELECT network FROM user_preferences".to_string(); + + let res = storage.get_all::(&query, 1)?; + + match res.get(0) { + Some(network) => Ok(network[0].clone()), + None => Err(AvailError::new( + AvailErrorType::LocalStorage, + "No network found".to_string(), + "No network found".to_string(), + )), + } +} + +/// Update network in user preferences +#[tauri::command(rename_all = "snake_case")] +pub fn update_network(network: EventNetwork) { + let storage = PersistentStorage::new().unwrap(); + + storage + .save( + vec![Box::new(network.to_string())], + "UPDATE user_preferences SET network = ?1".to_string(), + ) + .unwrap(); +} + +///get last sync height from user preferences +#[tauri::command(rename_all = "snake_case")] +pub fn get_last_sync() -> AvailResult { + let storage = PersistentStorage::new()?; + + let query = "SELECT last_sync FROM user_preferences".to_string(); + + let res = storage.get_all::(&query, 1)?; + + match res.get(0) { + Some(last_sync) => Ok(last_sync[0].to_owned()), + None => Err(AvailError::new( + AvailErrorType::LocalStorage, + "No last sync height found".to_string(), + "No last sync height found".to_string(), + )), + } +} + +///update last sync height in user preferences +pub fn update_last_sync(height: u32) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + storage.save( + vec![&height], + "UPDATE user_preferences SET last_sync = ?1".to_string(), + )?; + + Ok(()) +} + +fn handle_no_backup_found() -> AvailResult> { + let backup_flag = get_backup_flag()?; + + match backup_flag { + true => { + // TODO - store everything since the creation of time and then update backup height + + Err(AvailError::new( + AvailErrorType::LocalStorage, + "No last backup height found, your encrypted data is being backed up.".to_string(), + "No last backup height found, your encrypted data is being backed up".to_string(), + )) + } + false => Ok(Utc::now()), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_last_backup_sync() -> AvailResult> { + let storage = PersistentStorage::new()?; + + let query = "SELECT last_backup_sync FROM user_preferences".to_string(); + + let res = storage.get_all::>>(&query, 1)?; + + match res.get(0) { + Some(last_backup) => match last_backup[0] { + Some(last_backup) => Ok(last_backup.to_owned()), + None => handle_no_backup_found(), + }, + None => handle_no_backup_found(), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub fn update_last_backup_sync(timestamp: DateTime) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + storage.save( + vec![×tamp], + "UPDATE user_preferences SET last_backup_sync = ?1".to_string(), + )?; + + Ok(()) +} + +/// get last transactions sync time from user preferences +pub fn get_last_tx_sync() -> AvailResult { + let storage = PersistentStorage::new()?; + + let query = "SELECT last_tx_sync FROM user_preferences".to_string(); + + let res = storage.get_all::>(&query, 1)?; + + let last_tx_sync = res[0][0].clone().timestamp(); + + Ok(last_tx_sync) +} + +/// update last transactions sync time in user preferences +pub fn update_last_tx_sync(timestamp: DateTime) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + storage.save( + vec![×tamp], + "UPDATE user_preferences SET last_tx_sync = ?1".to_string(), + )?; + + Ok(()) +} + +/// get public address from view session +pub fn get_address() -> AvailResult> { + let storage = PersistentStorage::new()?; + let query = "SELECT address FROM user_preferences".to_string(); + + let res = storage.get_all::(&query, 1)?; + + match res.get(0) { + Some(address) => Ok(Address::::from_str(&address[0])?), + None => Err(AvailError::new( + AvailErrorType::LocalStorage, + "No address found".to_string(), + "No address found".to_string(), + )), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_address_string() -> AvailResult { + let storage = PersistentStorage::new()?; + let query = "SELECT address FROM user_preferences".to_string(); + + let res = storage.get_all::(&query, 1)?; + + match res.get(0) { + Some(address) => Ok(address[0].clone()), + None => Err(AvailError::new( + AvailErrorType::LocalStorage, + "No address found".to_string(), + "No address found".to_string(), + )), + } +} + +pub fn update_address(address: &str) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + storage.save( + vec![Box::new(address.to_string())], + "UPDATE user_preferences SET address = ?1".to_string(), + )?; + + Ok(()) +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_backup_flag() -> AvailResult { + let storage = PersistentStorage::new()?; + + let query = "SELECT backup FROM user_preferences".to_string(); + + let res = storage.get_all::(&query, 1)?; + + let backup = res[0].clone(); + + Ok(backup[0]) +} + +#[tauri::command(rename_all = "snake_case")] +pub fn update_local_backup_flag(backup: bool) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + storage.save( + vec![&backup], + "UPDATE user_preferences SET backup = ?1".to_string(), + )?; + + Ok(()) +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_language() -> AvailResult { + let storage = PersistentStorage::new()?; + + let query = "SELECT language FROM user_preferences".to_string(); + + let res = storage.get_all::(&query, 1)?; + + let language = match Languages::from_string_short(&res[0][0]) { + Some(language) => language, + None => Languages::English, + }; + + Ok(language) +} + +#[tauri::command(rename_all = "snake_case")] +pub fn update_language(language: Languages) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + storage.save( + vec![Box::new(language.to_string_short())], + "UPDATE user_preferences SET language = ?1".to_string(), + )?; + + Ok(()) +} + +#[test] +fn test_initial_user_preferences() { + initial_user_preferences( + true, + Some("Test".to_string()), + Some(1234), + false, + false, + "address".to_string(), + Languages::English, + ) + .unwrap(); + + let storage = PersistentStorage::new().unwrap(); + + let query = "SELECT auth_type FROM user_preferences".to_string(); + + let res = storage.get_all::(&query, 1).unwrap(); + + print!("{:?}", res[0][0]); + assert_eq!(res[0][0], "true".to_string()); +} + +#[test] +fn test_delete_user_preferences() { + delete_user_preferences().unwrap(); +} + +#[test] +fn test_change_auth_type() { + change_auth_type().unwrap(); + + let res = get_auth_type().unwrap(); + + assert_eq!(res, false); +} + +#[test] +fn test_get_last_sync() { + let res = get_last_sync().unwrap(); + + print!("{}", res); +} + +#[test] +fn test_update_last_sync() { + update_last_sync(88329u32).unwrap(); +} + +#[test] +fn test_get_username() { + let res = get_username().unwrap(); + + print!("{}", res); +} + +#[test] +fn test_get_network() { + let res = get_network().unwrap(); + + print!("{}", res); + assert_eq!(res, "testnet3".to_string()); +} + +#[test] +fn test_get_address() { + let address = get_address::().unwrap(); + + print!("{}", address); +} + +#[test] +fn test_get_address_string() { + let address = get_address_string().unwrap(); + + print!("{}", address); +} + +#[test] +fn test_get_backup_flag() { + let backup = get_backup_flag().unwrap(); + + print!("{}", backup); +} + +#[test] +fn test_update_backup_flag() { + update_local_backup_flag(true).unwrap(); +} diff --git a/src-tauri/src/services/local_storage/session.rs b/src-tauri/src/services/local_storage/session.rs new file mode 100644 index 00000000..ef0ace9e --- /dev/null +++ b/src-tauri/src/services/local_storage/session.rs @@ -0,0 +1,2 @@ +pub mod password; +pub mod view; diff --git a/src-tauri/src/services/local_storage/session/password.rs b/src-tauri/src/services/local_storage/session/password.rs new file mode 100644 index 00000000..2d84d188 --- /dev/null +++ b/src-tauri/src/services/local_storage/session/password.rs @@ -0,0 +1,75 @@ +use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; +use once_cell::sync::Lazy; +use std::{ + sync::{Arc, RwLock}, + time::{Duration, Instant}, +}; + +pub struct PassSession { + password: RwLock>, + expiration: RwLock, +} + +impl PassSession { + pub fn new() -> Self { + Self { + password: RwLock::new(None), + expiration: RwLock::new(Instant::now()), + } + } + + pub fn set_pass_session(&self, password: &str) -> AvailResult<()> { + let mut password_lock = self.password.write().unwrap(); + let mut expiration_lock = self.expiration.write().unwrap(); + *password_lock = Some(password.to_string()); + + // Set expiration to 5 minutes from now + *expiration_lock = Instant::now() + Duration::from_secs(5 * 60); + Ok(()) + } + + pub fn extend_session(&self) -> AvailResult<()> { + let mut expiration_lock = self.expiration.write().unwrap(); + // Extend expiration to 5 minutes from now + *expiration_lock = Instant::now() + Duration::from_secs(5 * 60); + Ok(()) + } + + pub fn get_instance(&self) -> AvailResult { + let expiration_lock = self.expiration.read().unwrap(); + if Instant::now() > *expiration_lock { + let mut password_lock = self.password.write().unwrap(); + *password_lock = None; // Clear the password as session expired + + return Err(AvailError::new( + AvailErrorType::Unauthorized, + "Session expired, please reauthenticate.".to_string(), + "Session expired, please reauthenticate.".to_string(), + )); + } + drop(expiration_lock); // Release the read lock before acquiring the write lock + + let password_lock = self.password.read().unwrap(); + match &*password_lock { + Some(password) => Ok(password.to_owned()), + None => Err(AvailError::new( + AvailErrorType::Unauthorized, + "Unauthorized, please reauthenticate.".to_string(), + "Unauthorized, please reauthenticate.".to_string(), + )), + } + } +} + +pub static PASS: Lazy> = Lazy::new(|| Arc::new(PassSession::new())); + +mod test_pass_session { + use super::*; + + #[test] + fn test_pass_session() { + PASS.set_pass_session("password").unwrap(); + let password = PASS.get_instance().unwrap(); + assert_eq!(password, "password"); + } +} diff --git a/src-tauri/src/services/local_storage/session/view.rs b/src-tauri/src/services/local_storage/session/view.rs new file mode 100644 index 00000000..b0ff8777 --- /dev/null +++ b/src-tauri/src/services/local_storage/session/view.rs @@ -0,0 +1,59 @@ +use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; +use once_cell::sync::Lazy; +use std::{ + str::FromStr, + sync::{Arc, RwLock}, +}; + +use snarkvm::prelude::{Network, ViewKey}; + +pub struct ViewSession { + view_key: RwLock>, +} + +impl ViewSession { + pub fn new() -> Self { + Self { + view_key: RwLock::new(None), + } + } + + pub fn set_view_session(&self, view_key: &str) -> AvailResult<()> { + let mut view_key_lock = self.view_key.write().unwrap(); + *view_key_lock = Some(view_key.to_string()); + Ok(()) + } + + pub fn get_instance(&self) -> AvailResult> { + let view_key_lock = self.view_key.read().unwrap(); + let view_key = match &*view_key_lock { + Some(view_key) => view_key, + None => { + return Err(AvailError::new( + AvailErrorType::Validation, + "View Key not found".to_string(), + "View Key not found".to_string(), + )) + } + }; + let view_key = ViewKey::::from_str(view_key)?; + Ok(view_key) + } +} + +pub static VIEWSESSION: Lazy> = Lazy::new(|| Arc::new(ViewSession::new())); + +mod test_view_session { + + use super::*; + use avail_common::models::constants::*; + use snarkvm::prelude::Testnet3; + + #[test] + fn test_view_session() { + let view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY).unwrap(); + VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); + let view_key = VIEWSESSION.get_instance::().unwrap(); + assert_eq!(view_key.to_string(), TESTNET3_VIEW_KEY); + } +} diff --git a/src-tauri/src/services/local_storage/storage_api.rs b/src-tauri/src/services/local_storage/storage_api.rs new file mode 100644 index 00000000..402d5df1 --- /dev/null +++ b/src-tauri/src/services/local_storage/storage_api.rs @@ -0,0 +1,6 @@ +pub mod deployment; +pub mod event; +pub mod records; +pub mod transaction; +pub mod transition; +// pub mod tokens; diff --git a/src-tauri/src/services/local_storage/storage_api/deployment.rs b/src-tauri/src/services/local_storage/storage_api/deployment.rs new file mode 100644 index 00000000..e26a821e --- /dev/null +++ b/src-tauri/src/services/local_storage/storage_api/deployment.rs @@ -0,0 +1,147 @@ +use chrono::{DateTime, Local}; +use snarkvm::prelude::{transactions::Transactions, Address, Network, Testnet3}; +use std::str::FromStr; + +use crate::models::{event::Event, pointers::deployment::DeploymentPointer}; +use crate::services::local_storage::encrypted_data::store_encrypted_data; +use crate::services::local_storage::{ + encrypted_data::{get_encrypted_data_by_flavour, get_encrypted_data_by_id}, + persistent_storage::get_network, + session::view::VIEWSESSION, +}; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::{ + encrypted_data::{EncryptedData, EncryptedDataTypeCommon, TransactionState}, + network::SupportedNetworks, + }, +}; + +/* -- Deployments -- */ +pub fn find_encrypt_store_deployments( + transactions: &Transactions, + height: u32, + timestamp: DateTime, + address: Address, + stored_transaction_ids: Vec, +) -> AvailResult> { + let deployment_pointers = transactions + .iter() + .map(|tx| { + if stored_transaction_ids.contains(&tx.id()) { + return None; + } + let deployment = tx.deployment(); + let owner = tx.owner(); + if let Some(deployment) = deployment { + let owner = owner.unwrap(); + match owner.address() == address { + true => { + let base_fee = match tx.base_fee_amount() { + Ok(fee) => fee, + Err(_) => return None, + }; + let priority_fee = match tx.priority_fee_amount() { + Ok(fee) => fee, + Err(_) => return None, + }; + let fee = *(base_fee + priority_fee) as f64 / 1000000.0; + + let deployment_pointer = DeploymentPointer::new( + Some(tx.id().to_owned()), + deployment.program_id().to_string(), + fee, + TransactionState::Confirmed, + Some(height), + None, + timestamp, + Some(timestamp), + None, + ); + + Some(deployment_pointer) + } + false => None, + } + } else { + None + } + }) + .filter_map(|x| x) + .collect::>(); + + let encrypted_deployments = deployment_pointers + .iter() + .map(|dp| { + let encrypted_dp = dp.to_encrypted_data(address)?; + store_encrypted_data(encrypted_dp.clone())?; + Ok(encrypted_dp) + }) + .collect::>>()?; + + Ok(encrypted_deployments) +} + +pub fn get_deployment_pointer(id: &str) -> AvailResult> { + let encrypted_deployment = get_encrypted_data_by_id(id)?; + + let deployment = decrypt_deployments::(vec![encrypted_deployment])?; + + Ok(deployment[0].to_owned()) +} + +// TODO - make generic to all encrypted data with Deserialize trait bound +pub fn decrypt_deployments( + encrypted_deployments: Vec, +) -> AvailResult>> { + let network = get_network()?; + + let v_key = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => VIEWSESSION.get_instance::()?, + _ => VIEWSESSION.get_instance::()?, + }; + + let deployments = encrypted_deployments + .iter() + .map(|x| { + let encrypted_data = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => x.to_enrypted_struct::()?, + _ => x.to_enrypted_struct::()?, + }; + + let deployment: DeploymentPointer = encrypted_data.decrypt(v_key)?; + + Ok(deployment) + }) + .collect::>>>()?; + + Ok(deployments) +} + +pub fn decrypt_deployment(encrypted_deployment: EncryptedData) -> AvailResult { + let v_key = VIEWSESSION.get_instance::()?; + + let db_id = match encrypted_deployment.id { + Some(id) => id.to_string(), + None => Err(AvailError::new( + AvailErrorType::Internal, + "No id found".to_string(), + "No Id Found".to_string(), + ))?, + }; + + let encrypted_data = encrypted_deployment.to_enrypted_struct::()?; + + let deployment: DeploymentPointer = encrypted_data.decrypt(v_key)?; + + deployment.to_event(&db_id) +} + +pub fn get_deployment_pointers() -> AvailResult>> { + let encrypted_deployments = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Deployment)?; + + decrypt_deployments(encrypted_deployments) +} + +mod deployment_storage_api_test {} diff --git a/src-tauri/src/services/local_storage/storage_api/event.rs b/src-tauri/src/services/local_storage/storage_api/event.rs new file mode 100644 index 00000000..fc3674eb --- /dev/null +++ b/src-tauri/src/services/local_storage/storage_api/event.rs @@ -0,0 +1,539 @@ +use std::cmp::max; + +use rusqlite::params; +use snarkvm::prelude::Network; + +use crate::models::pointers::{ + deployment::DeploymentPointer, transaction::TransactionPointer, transition::TransitionPointer, +}; +use crate::models::wallet_connect::get_event::GetEventsRequest; +use crate::models::{ + event::{AvailEvent, Event, SuccinctAvailEvent}, + storage::persistent::PersistentStorage, +}; +use crate::services::local_storage::{ + encrypted_data::{get_encrypted_data_by_id, handle_encrypted_data_query}, + persistent_storage::{get_address_string, get_network}, +}; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::encrypted_data::{EncryptedData, EncryptedDataTypeCommon}, +}; + +/// Gets an Event by its encrypted data id +pub fn get_event_raw(id: &str) -> AvailResult { + let encrypted_event = get_encrypted_data_by_id(id)?; + let event = match encrypted_event.flavour { + EncryptedDataTypeCommon::Transition => { + TransitionPointer::::decrypt_to_event(encrypted_event)? + } + EncryptedDataTypeCommon::Transaction => { + TransactionPointer::::decrypt_to_event(encrypted_event)? + } + EncryptedDataTypeCommon::Deployment => { + DeploymentPointer::::decrypt_to_event(encrypted_event)? + } + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Unknown encrypted data flavour".to_string(), + "Unknown Transaction Type".to_string(), + )) + } + }; + + Ok(event) +} + +/// Gets an Avail Event by its encrypted data id +pub fn get_avail_event_raw(id: &str) -> AvailResult { + let encrypted_event = get_encrypted_data_by_id(id)?; + let event = match encrypted_event.flavour { + EncryptedDataTypeCommon::Transition => { + TransitionPointer::::decrypt_to_avail_event(encrypted_event)? + } + EncryptedDataTypeCommon::Transaction => { + TransactionPointer::::decrypt_to_avail_event(encrypted_event)? + } + EncryptedDataTypeCommon::Deployment => { + DeploymentPointer::::decrypt_to_avail_event(encrypted_event)? + } + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Unknown encrypted data flavour".to_string(), + "Unknown Transaction Type".to_string(), + )) + } + }; + + Ok(event) +} + +/// Gets a Succinct Avail Event by its encrypted data id +pub fn get_succinct_avail_event_raw(id: &str) -> AvailResult { + let encrypted_event = get_encrypted_data_by_id(id)?; + let event = match encrypted_event.flavour { + EncryptedDataTypeCommon::Transition => { + TransitionPointer::::decrypt_to_succinct_avail_event(encrypted_event)? + } + EncryptedDataTypeCommon::Transaction => { + TransactionPointer::::decrypt_to_succinct_avail_event(encrypted_event)? + } + EncryptedDataTypeCommon::Deployment => { + DeploymentPointer::::decrypt_to_succinct_avail_event(encrypted_event)? + } + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Unknown encrypted data flavour".to_string(), + "Unknown Transaction Type".to_string(), + )) + } + }; + + Ok(event) +} + +pub fn get_events_raw(request: GetEventsRequest) -> AvailResult> { + let address = get_address_string()?; + let network = get_network()?; + + // Query for transitions and deployments + let transitions_deployments_query = format!( + "SELECT *, '[]' as json_program_ids, '[]' as json_function_ids FROM encrypted_data WHERE flavour IN ('{}','{}') AND owner='{}' AND network='{}'", + EncryptedDataTypeCommon::Transition.to_str(), + EncryptedDataTypeCommon::Deployment.to_str(), + address, + network + ); + + // Query for transactions + let transactions_query = format!( + "SELECT *, program_ids as json_program_ids, function_ids as json_function_ids FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", + EncryptedDataTypeCommon::Transaction.to_str(), + address, + network + ); + + // Applying filters + let mut common_filter_conditions = String::new(); + if let Some(filter) = request.filter { + if let Some(event_type) = filter.event_type { + common_filter_conditions + .push_str(&format!(" AND event_type='{}'", event_type.to_str())); + } + + if let Some(program_id) = filter.program_id { + // Adjust this to handle both cases (string equality for transitions/deployments and JSON array contains for transactions) + common_filter_conditions.push_str(&format!( + " AND (program_ids='{}' OR JSON_EXTRACT(json_program_ids, '$') LIKE '%{}%')", + program_id, program_id + )); + } + + if let Some(function_id) = filter.function_id { + // Similar adjustment for function_ids + common_filter_conditions.push_str(&format!( + " AND (function_ids='{}' OR JSON_EXTRACT(json_function_ids, '$') LIKE '%{}%')", + function_id, function_id + )); + } + } + + let transitions_deployments_query_with_filters = format!( + "{} {}", + transitions_deployments_query, common_filter_conditions + ); + + let transactions_query_with_filters = + format!("{} {}", transactions_query, common_filter_conditions); + + let mut combined_query = format!( + "{} UNION ALL {} ORDER BY created_at DESC", + transitions_deployments_query_with_filters, transactions_query_with_filters + ); + + let mut encrypted_data: Vec = vec![]; + + if let Some(page) = request.page { + let fetch_limit = (page * 6) + 6; + + combined_query = format!( + "{} UNION ALL {} ORDER BY created_at DESC LIMIT {}", + transitions_deployments_query_with_filters, + transactions_query_with_filters, + fetch_limit + ); + + let page_start = (page * 6) as usize; + let page_end = page_start + 6; + + let encrypted_data_result = handle_encrypted_data_query(&combined_query)?; + let page_encrypted_data = encrypted_data_result[page_start.min(encrypted_data_result.len()) + ..page_end.min(encrypted_data_result.len())] + .to_vec(); + encrypted_data = page_encrypted_data; + } else { + encrypted_data = handle_encrypted_data_query(&combined_query)?; + } + + let mut events: Vec = vec![]; + for encrypted_transaction in encrypted_data { + let event = match encrypted_transaction.flavour { + EncryptedDataTypeCommon::Transition => { + TransitionPointer::::decrypt_to_event(encrypted_transaction)? + } + EncryptedDataTypeCommon::Transaction => { + TransactionPointer::::decrypt_to_event(encrypted_transaction)? + } + EncryptedDataTypeCommon::Deployment => { + DeploymentPointer::::decrypt_to_event(encrypted_transaction)? + } + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Unknown encrypted data flavour".to_string(), + "Unknown Transaction Type".to_string(), + )) + } + }; + + events.push(event); + } + + Ok(events) +} + +// Get Avail Events with filter +pub fn get_avail_events_raw(request: GetEventsRequest) -> AvailResult> { + let address = get_address_string()?; + let network = get_network()?; + + // Query for transitions and deployments + let transitions_deployments_query = format!( + "SELECT *, '[]' as json_program_ids, '[]' as json_function_ids FROM encrypted_data WHERE flavour IN ('{}','{}') AND owner='{}' AND network='{}'", + EncryptedDataTypeCommon::Transition.to_str(), + EncryptedDataTypeCommon::Deployment.to_str(), + address, + network + ); + + // Query for transactions + let transactions_query = format!( + "SELECT *, program_ids as json_program_ids, function_ids as json_function_ids FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", + EncryptedDataTypeCommon::Transaction.to_str(), + address, + network + ); + + // Applying filters + let mut common_filter_conditions = String::new(); + if let Some(filter) = request.filter { + if let Some(event_type) = filter.event_type { + common_filter_conditions + .push_str(&format!(" AND event_type='{}'", event_type.to_str())); + } + + if let Some(program_id) = filter.program_id { + // Adjust this to handle both cases (string equality for transitions/deployments and JSON array contains for transactions) + common_filter_conditions.push_str(&format!( + " AND (program_ids='{}' OR JSON_EXTRACT(json_program_ids, '$') LIKE '%{}%')", + program_id, program_id + )); + } + + if let Some(function_id) = filter.function_id { + // Similar adjustment for function_ids + common_filter_conditions.push_str(&format!( + " AND (function_ids='{}' OR JSON_EXTRACT(json_function_ids, '$') LIKE '%{}%')", + function_id, function_id + )); + } + } + + let transitions_deployments_query_with_filters = format!( + "{} {}", + transitions_deployments_query, common_filter_conditions + ); + + let transactions_query_with_filters = + format!("{} {}", transactions_query, common_filter_conditions); + + let mut combined_query = format!( + "{} UNION ALL {} ORDER BY created_at DESC", + transitions_deployments_query_with_filters, transactions_query_with_filters + ); + + let mut encrypted_data: Vec = vec![]; + + if let Some(page) = request.page { + let fetch_limit = (page * 6) + 6; + + combined_query = format!( + "{} UNION ALL {} ORDER BY created_at DESC LIMIT {}", + transitions_deployments_query_with_filters, + transactions_query_with_filters, + fetch_limit + ); + + let page_start = (page * 6) as usize; + let page_end = page_start + 6; + + let encrypted_data_result = handle_encrypted_data_query(&combined_query)?; + let page_encrypted_data = encrypted_data_result[page_start.min(encrypted_data_result.len()) + ..page_end.min(encrypted_data_result.len())] + .to_vec(); + encrypted_data = page_encrypted_data; + } else { + encrypted_data = handle_encrypted_data_query(&combined_query)?; + } + + let mut events: Vec = vec![]; + + for encrypted_transaction in encrypted_data { + let event = match encrypted_transaction.flavour { + EncryptedDataTypeCommon::Transition => { + TransitionPointer::::decrypt_to_avail_event(encrypted_transaction)? + } + EncryptedDataTypeCommon::Transaction => { + TransactionPointer::::decrypt_to_avail_event(encrypted_transaction)? + } + EncryptedDataTypeCommon::Deployment => { + DeploymentPointer::::decrypt_to_avail_event(encrypted_transaction)? + } + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Unknown encrypted data flavour".to_string(), + "Unknown Transaction Type".to_string(), + )) + } + }; + + events.push(event); + } + + Ok(events) +} + +pub fn get_succinct_avail_events_raw( + request: GetEventsRequest, +) -> AvailResult> { + let address = get_address_string()?; + let network = get_network()?; + + // Query for transitions and deployments + let transitions_deployments_query = format!( + "SELECT *, '[]' as json_program_ids, '[]' as json_function_ids FROM encrypted_data WHERE flavour IN ('{}','{}') AND owner='{}' AND network='{}'", + EncryptedDataTypeCommon::Transition.to_str(), + EncryptedDataTypeCommon::Deployment.to_str(), + address, + network + ); + + // Query for transactions + let transactions_query = format!( + "SELECT *, program_ids as json_program_ids, function_ids as json_function_ids FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", + EncryptedDataTypeCommon::Transaction.to_str(), + address, + network + ); + + // Applying filters + let mut common_filter_conditions = String::new(); + if let Some(filter) = request.filter { + if let Some(event_type) = filter.event_type { + common_filter_conditions + .push_str(&format!(" AND event_type='{}'", event_type.to_str())); + } + + if let Some(program_id) = filter.program_id { + // Adjust this to handle both cases (string equality for transitions/deployments and JSON array contains for transactions) + common_filter_conditions.push_str(&format!( + " AND (program_ids='{}' OR JSON_EXTRACT(json_program_ids, '$') LIKE '%{}%')", + program_id, program_id + )); + } + + if let Some(function_id) = filter.function_id { + // Similar adjustment for function_ids + common_filter_conditions.push_str(&format!( + " AND (function_ids='{}' OR JSON_EXTRACT(json_function_ids, '$') LIKE '%{}%')", + function_id, function_id + )); + } + } + + let transitions_deployments_query_with_filters = format!( + "{} {}", + transitions_deployments_query, common_filter_conditions + ); + + let transactions_query_with_filters = + format!("{} {}", transactions_query, common_filter_conditions); + + let mut combined_query = format!( + "{} UNION ALL {} ORDER BY created_at DESC", + transitions_deployments_query_with_filters, transactions_query_with_filters + ); + + let mut encrypted_data: Vec = vec![]; + + if let Some(page) = request.page { + let fetch_limit = (page * 6) + 6; + + combined_query = format!( + "{} UNION ALL {} ORDER BY created_at DESC LIMIT {}", + transitions_deployments_query_with_filters, + transactions_query_with_filters, + fetch_limit + ); + + let page_start = (page * 6) as usize; + let page_end = page_start + 6; + + let encrypted_data_result = handle_encrypted_data_query(&combined_query)?; + let page_encrypted_data = encrypted_data_result[page_start.min(encrypted_data_result.len()) + ..page_end.min(encrypted_data_result.len())] + .to_vec(); + encrypted_data = page_encrypted_data; + } else { + encrypted_data = handle_encrypted_data_query(&combined_query)?; + } + + let mut events: Vec = vec![]; + + for encrypted_transaction in encrypted_data { + let event = match encrypted_transaction.flavour { + EncryptedDataTypeCommon::Transition => { + TransitionPointer::::decrypt_to_succinct_avail_event(encrypted_transaction)? + } + EncryptedDataTypeCommon::Transaction => { + TransactionPointer::::decrypt_to_succinct_avail_event(encrypted_transaction)? + } + EncryptedDataTypeCommon::Deployment => { + DeploymentPointer::::decrypt_to_succinct_avail_event(encrypted_transaction)? + } + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Unknown encrypted data flavour".to_string(), + "Unknown Transaction Type".to_string(), + )) + } + }; + + events.push(event); + } + + Ok(events) +} + +/* --Utilities-- */ + +/// Calculates how many pages of events are available +pub fn transaction_pages_available() -> AvailResult { + let storage = PersistentStorage::new()?; + + let address = get_address_string()?; + let network = get_network()?; + + let events_per_page = 6; + let count_query = " + SELECT COUNT(*) FROM encrypted_data + WHERE flavour IN (?,?,?) + AND owner = ? + AND network = ?"; + + let total_count: i64 = storage.conn.query_row( + count_query, + params![ + EncryptedDataTypeCommon::Transition.to_str(), + EncryptedDataTypeCommon::Transaction.to_str(), + EncryptedDataTypeCommon::Deployment.to_str(), + address, + network + ], + |row| row.get(0), + )?; + // Calculate the number of pages + let total_pages = max( + 1, + (total_count as f64 / events_per_page as f64).ceil() as i64, + ); + Ok(total_pages) +} + +#[cfg(test)] +mod events_tests { + use std::str::FromStr; + + use super::*; + use snarkvm::prelude::{PrivateKey, Testnet3, ToBytes, ViewKey}; + + use crate::{ + models::wallet_connect::get_event::EventsFilter, + services::local_storage::{persistent_storage::update_address, session::view::VIEWSESSION}, + }; + use avail_common::models::constants::TESTNET_PRIVATE_KEY; + + #[test] + fn test_get_event_raw() { + let event = get_event_raw::( + String::from("5aa9d8f2-7d74-40fc-ae64-457dc188d598").as_str(), + ) + .unwrap(); + println!("{:?}", event); + } + + #[test] + fn test_get_avail_event_raw() { + let event = get_avail_event_raw::( + String::from("5aa9d8f2-7d74-40fc-ae64-457dc188d598").as_str(), + ) + .unwrap(); + println!("{:?}", event); + } + + #[test] + fn test_get_events_raw() { + let event_filter = EventsFilter { + event_type: None, + program_id: None, + function_id: Some("transfer_public_to_private".to_string()), + }; + let request = GetEventsRequest { + filter: Some(event_filter), + page: Some(0), + }; + + let event = get_events_raw::(request).unwrap(); + println!("{:?}", event); + } + + #[test] + fn test_get_avail_events_raw() { + VIEWSESSION + .set_view_session("AViewKey1dRUJgozQcBf2rntQqoGYfViNy4A3Khx9RZVwuX3kSNCx") + .unwrap(); + let event = get_avail_events_raw::(GetEventsRequest::default()).unwrap(); + println!("{:?}", event); + } + + #[test] + fn test_get_succinct_avail_events_raw() { + VIEWSESSION + .set_view_session("AViewKey1dRUJgozQcBf2rntQqoGYfViNy4A3Khx9RZVwuX3kSNCx") + .unwrap(); + let event = get_succinct_avail_events_raw::(GetEventsRequest::default()).unwrap(); + println!("{:?}", event); + } + + #[test] + fn test_transaction_pages_available() { + let event_pages = transaction_pages_available().unwrap(); + println!("{:?}", event_pages); + } +} diff --git a/src-tauri/src/services/local_storage/storage_api/records.rs b/src-tauri/src/services/local_storage/storage_api/records.rs new file mode 100644 index 00000000..380cb396 --- /dev/null +++ b/src-tauri/src/services/local_storage/storage_api/records.rs @@ -0,0 +1,641 @@ +use std::str::FromStr; + +use avail_common::errors::AvailError; +use snarkvm::circuit::integers::Integer; +use snarkvm::circuit::{Identifier, Inject}; +use snarkvm::prelude::{ + bail, Address, AleoID, Entry, Field, Literal, Network, Plaintext, Testnet3, ToField, +}; + +use crate::api::encrypted_data::update_data; +use crate::models::pointers::record::{AvailRecord, Metadata, Pointer}; +use crate::models::storage::persistent::PersistentStorage; +use crate::models::wallet_connect::records::{GetRecordsRequest, RecordFilterType}; +use crate::services::local_storage::encrypted_data::{ + get_encrypted_data_by_id, get_encrypted_data_by_nonce, handle_encrypted_data_query, + update_encrypted_data_spent_by_id, +}; +use crate::services::local_storage::persistent_storage::get_address_string; +use crate::services::local_storage::tokens::{add_balance, subtract_balance}; +use crate::services::local_storage::{ + encrypted_data::{get_encrypted_data_by_flavour, store_encrypted_data}, + persistent_storage::{get_address, get_network}, + session::view::VIEWSESSION, +}; + +use avail_common::{ + errors::AvailResult, + models::{ + constants::{TRANSITION_PREFIX, TX_PREFIX}, + encrypted_data::{EncryptedData, EncryptedDataTypeCommon, RecordTypeCommon}, + traits::encryptable::Encryptable, + }, +}; + +/// Encrypts record pointers using the wallet owner's address and stores them in persistent storage +pub fn encrypt_and_store_records( + record_pointers: Vec>, + address: Address, +) -> AvailResult> { + let encrypted_records = record_pointers + .iter() + .map(|record| { + let encrypted_record = record.to_encrypted_data(address)?; + + store_encrypted_data(encrypted_record.clone())?; + + Ok(encrypted_record) + }) + .collect::>>()?; + + Ok(encrypted_records) +} + +fn decrypt_record_pointers( + encrypted_data: Vec, +) -> AvailResult>> { + let view_key = VIEWSESSION.get_instance::()?; + + let records = encrypted_data + .iter() + .map(|x| { + let encrypted_data = x.to_enrypted_struct::()?; + + let record: AvailRecord = encrypted_data.decrypt(view_key)?; + + Ok(record) + }) + .collect::>>>()?; + + Ok(records) +} + +pub fn get_record_pointers( + request: GetRecordsRequest, +) -> AvailResult<(Vec>, Vec)> { + // TODO - use address to filter when supporting hd wallets + let address = match request.address() { + Some(address) => address.clone(), + None => get_address_string()?, + }; + + let mut base_query = format!( + "SELECT * FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", + EncryptedDataTypeCommon::Record.to_str(), + address, + get_network()?, + ); + + if let Some(filter) = request.filter() { + match RecordFilterType::from_string(filter.record_type()) { + RecordFilterType::Spent => base_query.push_str(" AND spent=true"), + RecordFilterType::Unspent => base_query.push_str(" AND spent=false"), + _ => (), + } + + let program_ids = filter.program_ids(); + if !program_ids.is_empty() { + let program_ids_list = program_ids + .iter() + .map(|id| format!("'{}'", id)) + .collect::>() + .join(", "); + base_query.push_str(&format!(" AND program_ids IN ({})", program_ids_list)); + } + + match filter.function_id() { + Some(function_id) => { + base_query.push_str(&format!(" AND function_ids='{}'", function_id)); + } + None => (), + } + + match filter.record_name() { + Some(record_name) => { + base_query.push_str(&format!(" AND record_name='{}'", record_name)); + } + None => (), + } + } + + if let Some(page) = request.page() { + base_query.push_str(&format!(" LIMIT 50 OFFSET {}", page * 50)); + } + + let encrypted_records = handle_encrypted_data_query(&base_query)?; + + let encrypted_record_pointers_ids = encrypted_records + .iter() + .map(|x| x.id.clone().unwrap().to_string()) + .collect::>(); + + let record_pointers = decrypt_record_pointers::(encrypted_records)?; + + Ok((record_pointers, encrypted_record_pointers_ids)) +} + +pub fn get_page_count_for_filter(request: GetRecordsRequest) -> AvailResult { + let address = match request.address() { + Some(address) => address.clone(), + None => get_address_string()?, + }; + + let db = PersistentStorage::new()?; + + let mut base_query = format!( + "SELECT COUNT(*) FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", + EncryptedDataTypeCommon::Record.to_str(), + address, + get_network()?, + ); + + if let Some(filter) = request.filter() { + match RecordFilterType::from_string(filter.record_type()) { + RecordFilterType::Spent => base_query.push_str(" AND spent=true"), + RecordFilterType::Unspent => base_query.push_str(" AND spent=false"), + _ => (), + } + + let program_ids = filter.program_ids(); + if !program_ids.is_empty() { + let program_ids_list = program_ids + .iter() + .map(|id| format!("'{}'", id)) + .collect::>() + .join(", "); + base_query.push_str(&format!(" AND program_ids IN ({})", program_ids_list)); + } + + match filter.function_id() { + Some(function_id) => { + base_query.push_str(&format!(" AND function_ids='{}'", function_id)); + } + None => (), + } + + match filter.record_name() { + Some(record_name) => { + base_query.push_str(&format!(" AND record_name='{}'", record_name)); + } + None => (), + } + } + let mut query_statement = db.conn.prepare(base_query.as_str())?; + let count: i32 = query_statement.query_row([], |row| row.get(0))?; + + let page_count = count / 50; + + Ok(page_count) +} + +pub fn get_record_pointers_ids() -> AvailResult<(Vec>, Vec)> { + let encrypted_records = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record)?; + + let encrypted_record_pointers_ids = encrypted_records + .iter() + .map(|x| x.id.clone().unwrap().to_string()) + .collect::>(); + + let record_pointers = decrypt_record_pointers::(encrypted_records)?; + + Ok((record_pointers, encrypted_record_pointers_ids)) +} + +pub fn get_record_pointers_for_record_type( + record_type: RecordTypeCommon, + address: &str, +) -> AvailResult<(Vec>, Vec)> { + let network = get_network()?; + + let query = format!( + "SELECT * FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}' AND record_type='{}';", + EncryptedDataTypeCommon::Record.to_str(), + address, + network, + record_type.to_str() + ); + + let encrypted_record_pointers = handle_encrypted_data_query(&query)?; + + let encrypted_record_pointers_ids = encrypted_record_pointers + .iter() + .map(|x| x.id.unwrap().to_string()) + .collect::>(); + + let record_pointers = decrypt_record_pointers::(encrypted_record_pointers)?; + + Ok((record_pointers, encrypted_record_pointers_ids)) +} + +/* Utilities */ + +/// Update record spent status on local storage via nonce +pub fn update_record_spent_local_via_nonce( + nonce: &str, + spent: bool, +) -> AvailResult<()> { + let address = get_address::()?; + + let v_key = VIEWSESSION.get_instance::()?; + + if let Some(encrypted_data) = get_encrypted_data_by_nonce(nonce)? { + let encrypted_data_id = match encrypted_data.id { + Some(id) => id.to_string(), + None => { + return Err(AvailError::new( + avail_common::errors::AvailErrorType::Internal, + "No id found for encrypted data".to_string(), + "No id found for encrypted data".to_string(), + )) + } + }; + + println!( + "Updating record spent {} status for id: {}", + spent, encrypted_data_id + ); + + let encrypted_struct = encrypted_data.to_enrypted_struct::()?; + + let mut record_pointer: AvailRecord = encrypted_struct.decrypt(v_key)?; + + if record_pointer.metadata.spent == spent { + return Ok(()); + } + + record_pointer.metadata.spent = spent; + if record_pointer.clone().metadata.record_type == RecordTypeCommon::Tokens + || record_pointer.clone().metadata.record_type == RecordTypeCommon::AleoCredits + { + let record = record_pointer.clone().to_record()?; + let record_data_keys = record.data().clone().into_keys(); + let record_name = record_pointer.clone().metadata.name; + for key in record_data_keys { + let is_key: bool = matches!(key.to_string().as_str(), "amount" | "microcredits"); + + if is_key { + let balance_entry = match record.data().get(&key.clone()) { + Some(bal) => Ok(bal), + None => Err(()), + }; + + let balance = match balance_entry.unwrap() { + Entry::Private(Plaintext::Literal(Literal::::U64(amount), _)) => { + **amount + } + Entry::Public(Plaintext::Literal(Literal::::U64(amount), _)) => **amount, + Entry::Constant(Plaintext::Literal(Literal::::U64(amount), _)) => { + **amount + } + _ => 0u64, + }; + + //let balance_field = balance_f.to_be_bytes(); + //let balance = u64::from_be_bytes(balance_field); + + let _ = match spent { + true => subtract_balance(&record_name, &balance.to_string(), v_key)?, + false => add_balance(&record_name, &balance.to_string(), v_key)?, + }; + } + } + } + let updated_record_pointer = record_pointer.encrypt_for(address)?; + + update_encrypted_data_spent_by_id( + &encrypted_data_id, + &updated_record_pointer.cipher_text.to_string(), + &updated_record_pointer.nonce.to_string(), + spent, + )?; + } + + Ok(()) +} + +pub fn check_if_record_exists(nonce: &str) -> AvailResult { + let encrypted_data = get_encrypted_data_by_nonce(nonce)?; + + if let Some(encrypted_data) = encrypted_data { + Ok(encrypted_data.id.is_some()) + } else { + Ok(false) + } +} + +/// Update record spent status on local storage +pub fn update_record_spent_local(id: &str, spent: bool) -> AvailResult<()> { + let address = get_address::()?; + + let v_key = VIEWSESSION.get_instance::()?; + + let encrypted_data = get_encrypted_data_by_id(id)?; + + let encrypted_struct = encrypted_data.to_enrypted_struct::()?; + + let mut record_pointer: AvailRecord = encrypted_struct.decrypt(v_key)?; + + if record_pointer.metadata.spent == spent { + return Ok(()); + } + + record_pointer.metadata.spent = spent; + if record_pointer.clone().metadata.record_type == RecordTypeCommon::Tokens + || record_pointer.clone().metadata.record_type == RecordTypeCommon::AleoCredits + { + let record = record_pointer.clone().to_record()?; + let record_data_keys = record.data().clone().into_keys(); + let record_name = record_pointer.clone().metadata.name; + for key in record_data_keys { + let is_key: bool = matches!(key.to_string().as_str(), "amount" | "microcredits"); + + if is_key { + let balance_entry = match record.data().get(&key.clone()) { + Some(bal) => Ok(bal), + None => Err(()), + }; + + let balance = match balance_entry.unwrap() { + Entry::Private(Plaintext::Literal(Literal::::U64(amount), _)) => **amount, + Entry::Public(Plaintext::Literal(Literal::::U64(amount), _)) => **amount, + Entry::Constant(Plaintext::Literal(Literal::::U64(amount), _)) => **amount, + _ => 0u64, + }; + + //let balance_field = balance_f.to_be_bytes(); + //let balance = u64::from_be_bytes(balance_field); + + let _ = match spent { + true => subtract_balance(&record_name, &balance.to_string(), v_key)?, + false => add_balance(&record_name, &balance.to_string(), v_key)?, + }; + } + } + } + let updated_record_pointer = record_pointer.encrypt_for(address)?; + + update_encrypted_data_spent_by_id( + id, + &updated_record_pointer.cipher_text.to_string(), + &updated_record_pointer.nonce.to_string(), + spent, + )?; + Ok(()) +} + +/// Update record spent on encrypted backup after local storage has been updated +pub async fn update_records_spent_backup(ids: Vec) -> AvailResult<()> { + let encrypted_data = ids + .iter() + .map(|id| { + let data = get_encrypted_data_by_id(id)?; + Ok(data) + }) + .collect::>>()?; + + update_data(encrypted_data, ids).await?; + // update status server side via id + Ok(()) +} + +///For Testing purposes +pub fn get_test_record_pointer() -> AvailRecord { + let test_transaction_id = AleoID::, TX_PREFIX>::from_str( + "at1zux4zw83dayxtndd58skuy7qq7xg0d6ez86ak9zlqh2zru4kgggqjys70g", + ) + .unwrap(); + let test_transition_id = AleoID::, TRANSITION_PREFIX>::from_str( + "au1070w2eknk90ldz2rs88p8erdjq5we4787hr702pf3lmzxsr4kg8sr5lran", + ) + .unwrap(); + + let test_record_pointer: AvailRecord = AvailRecord { + pointer: Pointer { + block_height: 10u32, + transaction_id: test_transaction_id, + transition_id: test_transition_id, + commitment: "test_commitment".to_string(), + tag: "test_tag".to_string(), + index: 0u8, + owner: "address".to_string(), + }, + metadata: Metadata { + record_type: RecordTypeCommon::AleoCredits, + program_id: "credits.aleo".to_string(), + function_id: "transfer_public_to_private".to_string(), + spent: false, + name: "credits.record".to_string(), + nonce: "test_nonce".to_string(), + }, + }; + + test_record_pointer +} + +#[cfg(test)] +mod records_storage_api_tests { + use super::*; + use crate::api::encrypted_data::{delete_all_server_storage, post_encrypted_data}; + use crate::models::storage::languages::Languages; + use crate::models::wallet_connect::records::{wc_Record, RecordWithPlaintext, RecordsFilter}; + + use crate::services::local_storage::encrypted_data::{ + delete_user_encrypted_data, drop_encrypted_data_table, + }; + + use crate::services::local_storage::{ + encrypted_data::initialize_encrypted_data_table, + persistent_storage::{delete_user_preferences, initial_user_preferences, update_address}, + session::view::VIEWSESSION, + }; + use avail_common::models::constants::*; + use snarkvm::prelude::{PrivateKey, ToBytes, ViewKey}; + + fn test_setup_prerequisites() { + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let view_key = ViewKey::::try_from(&pk).unwrap(); + + delete_user_encrypted_data().unwrap(); + delete_user_preferences().unwrap(); + // initialize the user preferences + initial_user_preferences( + false, + None, + None, + false, + false, + view_key.to_address().to_string(), + Languages::English, + ) + .unwrap(); + initialize_encrypted_data_table().unwrap(); + + VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); + } + + #[test] + fn test_store_view_session() { + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let view_key = ViewKey::::try_from(&pk).unwrap(); + + VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); + } + + #[test] + fn test_encrypt_and_store_records() { + test_setup_prerequisites(); + + let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); + let test_record_pointer = get_test_record_pointer(); + + let encrypted_records = + encrypt_and_store_records::(vec![test_record_pointer], address).unwrap(); + + print!("{:?}", encrypted_records); + assert_eq!(encrypted_records.len(), 1); + } + + #[test] + fn test_get_record_pointers() { + // test_store_view_session(); + + VIEWSESSION + .set_view_session("AViewKey1pViDeDV8dT1yTCdzU6ojxh8GdFDadSasRpk6mZdyz8mh") + .unwrap(); + + //let test_record_pointer = get_test_record_pointer(); + + let record_filter = RecordsFilter::new( + vec!["credits.aleo".to_string()], + None, + RecordFilterType::All, + Some("credits.record".to_string()), + ); + + let request = GetRecordsRequest::new(None, Some(record_filter), None); + let (pointers, _ids) = get_record_pointers::(request).unwrap(); + + print!("Pointers {:?}", pointers); + + // assert!(pointers == vec![test_record_pointer]); + } + + #[test] + fn test_get_record_pointers_for_record_type() { + test_store_view_session(); + let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); + let test_record_pointer = get_test_record_pointer(); + + let pointers = get_record_pointers_for_record_type::( + RecordTypeCommon::AleoCredits, + &address.to_string(), + ) + .unwrap(); + + print!("Pointers \n {:?}", pointers); + + assert!(pointers.0 == vec![test_record_pointer]); + } + + #[test] + fn test_get_record_pointer_for_program_id() { + test_store_view_session(); + let test_record_pointer = get_test_record_pointer(); + let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); + + let record_filter = RecordsFilter::new( + vec!["credits.aleo".to_string()], + None, + RecordFilterType::All, + None, + ); + + let request = GetRecordsRequest::new(Some(address.to_string()), Some(record_filter), None); + + let (pointers, _ids) = get_record_pointers::(request).unwrap(); + + print!("Pointers \n {:?}", pointers); + + assert!(pointers == vec![test_record_pointer]); + } + + #[test] + fn test_get_record_pointer_for_program_id_and_function_id() { + test_store_view_session(); + let test_record_pointer = get_test_record_pointer(); + let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); + + let record_filter = RecordsFilter::new( + vec!["credits.aleo".to_string()], + Some("transfer_public_to_private".to_string()), + RecordFilterType::All, + None, + ); + + let request = GetRecordsRequest::new(Some(address.to_string()), Some(record_filter), None); + + let (pointers, _ids) = get_record_pointers::(request).unwrap(); + + print!("Pointers \n {:?}", pointers); + + assert!(pointers == vec![test_record_pointer]); + } + + #[test] + fn test_get_record_pointer_for_program_id_and_record_name() { + test_store_view_session(); + let test_record_pointer = get_test_record_pointer(); + let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); + let record_filter = RecordsFilter::new( + vec!["credits.aleo".to_string()], + None, + RecordFilterType::All, + Some("credits.record".to_string()), + ); + + let request = GetRecordsRequest::new(Some(address.to_string()), Some(record_filter), None); + let (pointers, _ids) = get_record_pointers::(request).unwrap(); + + print!("Pointers \n {:?}", pointers); + drop_encrypted_data_table().unwrap(); + assert!(pointers == vec![test_record_pointer]); + } + + #[test] + fn test_x() { + let test_record_pointer = get_test_record_pointer(); + RecordWithPlaintext::from_record_pointer(test_record_pointer, "id".to_string()).unwrap(); + } + + #[tokio::test] + async fn test_update_record_status() { + test_setup_prerequisites(); + + let test_pointer = get_test_record_pointer(); + let address = get_address::().unwrap(); + + let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); + + post_encrypted_data(encrypted_record.clone()).await.unwrap(); + + let res = update_records_spent_backup::(vec![encrypted_record[0] + .id + .unwrap() + .to_string()]) + .await + .unwrap(); + println!("{:?}", res); + + delete_all_server_storage().await.unwrap(); + } + + #[test] + fn test_check_if_record_exists() { + VIEWSESSION + .set_view_session("AViewKey1myvhAr2nes8MF1y8gPV19azp4evwsBR4CqyzAi62nufW") + .unwrap(); + + let res = check_if_record_exists::("").unwrap(); + println!("{:?}", res); + } +} diff --git a/src-tauri/src/services/local_storage/storage_api/transaction.rs b/src-tauri/src/services/local_storage/storage_api/transaction.rs new file mode 100644 index 00000000..3bfa303e --- /dev/null +++ b/src-tauri/src/services/local_storage/storage_api/transaction.rs @@ -0,0 +1,471 @@ +use chrono::{DateTime, Local, Utc}; +use snarkvm::prelude::Network; + +use crate::models::{ + event::Event, + pointers::{ + deployment::DeploymentPointer, transaction::TransactionPointer, + transition::TransitionPointer, + }, +}; +use crate::services::local_storage::encrypted_data::{ + get_encrypted_data_by_id, handle_encrypted_data_query, handle_encrypted_data_query_params, + update_encrypted_transaction_state_by_id, +}; +use crate::services::local_storage::{ + encrypted_data::get_encrypted_data_by_flavour, + persistent_storage::{get_address, get_network}, + session::view::VIEWSESSION, +}; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::encrypted_data::{EncryptedData, EncryptedDataTypeCommon, TransactionState}, +}; + +use super::{deployment::get_deployment_pointer, records::update_record_spent_local_via_nonce}; + +pub fn get_transactions_exec() -> AvailResult>> { + let encrypted_transactions = + get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transaction)?; + + let transactions = decrypt_transactions_exec(encrypted_transactions)?; + + Ok(transactions) +} + +pub fn get_transaction_pointer(id: &str) -> AvailResult> { + let encrypted_transaction = get_encrypted_data_by_id(id)?; + + let transaction = decrypt_transactions_exec::(vec![encrypted_transaction])?; + + Ok(transaction[0].to_owned()) +} + +pub fn decrypt_transactions_exec( + encrypted_transactions: Vec, +) -> AvailResult>> { + let v_key = VIEWSESSION.get_instance::()?; + + let transactions = encrypted_transactions + .iter() + .map(|x| { + let encrypted_data = x.to_enrypted_struct::()?; + + let tx_in: TransactionPointer = encrypted_data.decrypt(v_key)?; + + Ok(tx_in) + }) + .collect::>>>()?; + + Ok(transactions) +} + +pub fn decrypt_transaction_exec(encrypted_tx: EncryptedData) -> AvailResult { + let v_key = VIEWSESSION.get_instance::()?; + + let encrypted_data = encrypted_tx.to_enrypted_struct::()?; + + let tx_out: TransactionPointer = encrypted_data.decrypt(v_key)?; + + let event_id = match encrypted_tx.id { + Some(id) => id.to_string(), + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "No event id found".to_string(), + "No event id found".to_string(), + )) + } + }; + + tx_out.to_event(&event_id) +} + +/* Utilities */ +// get all transactions from a certain synced_on date forward and return Vector of transaction id string +pub fn get_tx_ids_from_date( + date: DateTime, +) -> AvailResult> { + let address = get_address::()?; + let network = get_network()?; + + // get a timestamp from 2 hours ago + let timestamp = date.with_timezone(&Utc); + let timestamp_2_hours_ago = timestamp - chrono::Duration::hours(2); + + let query = format!( + "SELECT * FROM encrypted_data WHERE flavour IN ('{}','{}','{}') AND owner='{}' AND network='{}' AND created_at >= ?1", + EncryptedDataTypeCommon::Transition.to_str(), + EncryptedDataTypeCommon::Transaction.to_str(), + EncryptedDataTypeCommon::Deployment.to_str(), + address, + network + ); + + let encrypted_transactions = + handle_encrypted_data_query_params(&query, vec![timestamp_2_hours_ago])?; + + let mut transaction_ids: Vec = Vec::new(); + + for encrypted_transaction in encrypted_transactions { + let encrypted_struct = encrypted_transaction.to_enrypted_struct::()?; + match encrypted_transaction.flavour { + EncryptedDataTypeCommon::Transition => { + let transition: TransitionPointer = + encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; + transaction_ids.push(transition.transaction_id); + } + EncryptedDataTypeCommon::Transaction => { + let tx_exec: TransactionPointer = + encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; + if let Some(id) = tx_exec.transaction_id() { + transaction_ids.push(id); + } + } + EncryptedDataTypeCommon::Deployment => { + let deployment: DeploymentPointer = + encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; + if let Some(id) = deployment.id { + transaction_ids.push(id); + } + } + _ => {} + }; + } + + Ok(transaction_ids) +} + +pub fn get_transaction_ids() -> AvailResult> { + let address = get_address::()?; + let network = get_network()?; + + let query = format!( + "SELECT * FROM encrypted_data WHERE flavour IN ('{}','{}','{}') AND owner='{}' AND network='{}'", + EncryptedDataTypeCommon::Transition.to_str(), + EncryptedDataTypeCommon::Transaction.to_str(), + EncryptedDataTypeCommon::Deployment.to_str(), + address, + network + ); + + let encrypted_transactions = handle_encrypted_data_query(&query)?; + + let mut transaction_ids: Vec = Vec::new(); + + for encrypted_transaction in encrypted_transactions { + let encrypted_struct = encrypted_transaction.to_enrypted_struct::()?; + match encrypted_transaction.flavour { + EncryptedDataTypeCommon::Transition => { + let transition: TransitionPointer = + encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; + transaction_ids.push(transition.transaction_id); + } + EncryptedDataTypeCommon::Transaction => { + let tx_exec: TransactionPointer = + encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; + + if let Some(id) = tx_exec.transaction_id() { + transaction_ids.push(id); + } + } + EncryptedDataTypeCommon::Deployment => { + let deployment: DeploymentPointer = + encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; + if let Some(id) = deployment.id { + transaction_ids.push(id); + } + } + _ => {} + }; + } + + Ok(transaction_ids) +} + +pub fn get_unconfirmed_and_failed_transaction_ids( +) -> AvailResult> { + let address = get_address::()?; + let network = get_network()?; + + let query = format!( + "SELECT * FROM encrypted_data WHERE flavour IN ('{}','{}','{}') AND state IN ('{}','{}') AND owner='{}' AND network='{}'", + EncryptedDataTypeCommon::Transition.to_str(), + EncryptedDataTypeCommon::Transaction.to_str(), + EncryptedDataTypeCommon::Deployment.to_str(), + TransactionState::Pending.to_str(), + TransactionState::Failed.to_str(), + address, + network + ); + + let encrypted_transactions = handle_encrypted_data_query(&query)?; + + let mut transaction_ids: Vec<(N::TransactionID, String)> = Vec::new(); + + for encrypted_transaction in encrypted_transactions { + let encrypted_struct = encrypted_transaction.to_enrypted_struct::()?; + match encrypted_transaction.flavour { + EncryptedDataTypeCommon::Transition => { + let transition: TransitionPointer = + encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; + if let Some(id) = encrypted_transaction.id { + transaction_ids.push((transition.transaction_id, id.to_string())); + } + } + EncryptedDataTypeCommon::Transaction => { + let tx_exec: TransactionPointer = + encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; + + if let Some(tx_id) = tx_exec.transaction_id() { + if let Some(id) = encrypted_transaction.id { + transaction_ids.push((tx_id, id.to_string())); + } + } + } + EncryptedDataTypeCommon::Deployment => { + let deployment: DeploymentPointer = + encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; + if let Some(tx_id) = deployment.id { + if let Some(id) = encrypted_transaction.id { + transaction_ids.push((tx_id, id.to_string())); + } + } + } + _ => {} + }; + } + + Ok(transaction_ids) +} + +// gets unconfirmed transactions that have been unconfirmed for more than 10 minutes +fn get_expired_unconfirmed_transactions() -> AvailResult> { + let address = get_address::()?; + let network = get_network()?; + + let query = format!( + "SELECT * FROM encrypted_data WHERE flavour IN ('{}','{}','{}') AND state='{}' AND owner='{}' AND network='{}'", + EncryptedDataTypeCommon::Transition.to_str(), + EncryptedDataTypeCommon::Transaction.to_str(), + EncryptedDataTypeCommon::Deployment.to_str(), + TransactionState::Pending.to_str(), + address, + network + ); + + let now = Local::now(); + let encrypted_data = handle_encrypted_data_query(&query)?; + let mut encrypted_transactions_to_decrypt: Vec = vec![]; + + for encrypted_data in encrypted_data { + if now + .signed_duration_since(encrypted_data.created_at) + .num_minutes() + > 10 + { + println!("{:?}", encrypted_data.transaction_state.clone()); + encrypted_transactions_to_decrypt.push(encrypted_data); + } + } + Ok(encrypted_transactions_to_decrypt) +} + +// This function should get unconfirmed encryped and check if they have been unconfirmed for more than 10 minutes +// If they have this should update to failed and the records related to the transaction should be updated to unspent +pub fn check_unconfirmed_transactions() -> AvailResult<()> { + let expired_transactions = get_expired_unconfirmed_transactions::()?; + + for expired_transaction in expired_transactions { + let encrypted_struct = expired_transaction.to_enrypted_struct::()?; + match expired_transaction.flavour { + EncryptedDataTypeCommon::Transaction => { + let tx_exec: TransactionPointer = + encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; + + if let Some(id) = expired_transaction.id { + handle_transaction_failed::(&id.to_string())?; + } + + let spent_record_nonces = tx_exec.spent_record_pointers_nonces(); + for nonce in spent_record_nonces { + update_record_spent_local_via_nonce::(&nonce, false)?; + } + } + EncryptedDataTypeCommon::Deployment => { + let deployment: DeploymentPointer = + encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; + + if let Some(id) = expired_transaction.id { + handle_deployment_failed::(&id.to_string())?; + } + + if let Some(fee_nonce) = deployment.spent_fee_nonce { + update_record_spent_local_via_nonce::(fee_nonce.as_str(), false)?; + } + } + _ => {} + }; + } + + Ok(()) +} + +pub fn handle_transaction_failed(pointer_id: &str) -> AvailResult<()> { + let address = get_address::()?; + let mut transaction_pointer = get_transaction_pointer::(pointer_id)?; + + transaction_pointer.update_failed_transaction( + "Transaction remained unconfirmed and failed, no records were spent.".to_string(), + ); + + let encrypted_failed_transaction = transaction_pointer.to_encrypted_data(address)?; + + update_encrypted_transaction_state_by_id( + pointer_id, + &encrypted_failed_transaction.ciphertext, + &encrypted_failed_transaction.nonce, + TransactionState::Failed, + )?; + + Ok(()) +} + +pub fn handle_deployment_failed(pointer_id: &str) -> AvailResult<()> { + let address = get_address::()?; + let mut deployment_pointer = get_deployment_pointer::(pointer_id)?; + + deployment_pointer.update_failed_deployment( + "Deployment remained unconfirmed and failed, no records were spent.".to_string(), + ); + + let encrypted_failed_deployment = deployment_pointer.to_encrypted_data(address)?; + + update_encrypted_transaction_state_by_id( + pointer_id, + &encrypted_failed_deployment.ciphertext, + &encrypted_failed_deployment.nonce, + TransactionState::Failed, + )?; + + Ok(()) +} + +#[cfg(test)] +mod tx_out_storage_api_tests { + use super::*; + use avail_common::models::{ + constants::*, + encrypted_data::{EventTypeCommon, TransactionState}, + }; + use chrono::Local; + use snarkvm::prelude::{Address, AleoID, Field, PrivateKey, Testnet3, ToBytes, ViewKey}; + use std::str::FromStr; + use uuid::Uuid; + + use crate::services::local_storage::{ + encrypted_data::{ + delete_user_encrypted_data, initialize_encrypted_data_table, store_encrypted_data, + }, + session::view::VIEWSESSION, + }; + + #[test] + fn test_store_view_session() { + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let view_key = ViewKey::::try_from(&pk).unwrap(); + + VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); + } + + #[test] + fn test_store_tx_out() { + delete_user_encrypted_data().unwrap(); + initialize_encrypted_data_table().unwrap(); + + let test_transaction_id = AleoID::, TX_PREFIX>::from_str( + "at1zux4zw83dayxtndd58skuy7qq7xg0d6ez86ak9zlqh2zru4kgggqjys70g", + ) + .unwrap(); + + let test_transaction_out = TransactionPointer::new( + Some("Test_User".to_string()), + Some(test_transaction_id), + TransactionState::Confirmed, + Some(100u32), + Some("test_program_id".to_string()), + Some("test_function_id".to_string()), + vec![], + vec![], + Local::now(), + Some(Local::now() + chrono::Duration::seconds(40)), + None, + EventTypeCommon::Send, + None, + None, + None, + ); + + let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); + let id = Uuid::new_v4(); + + let encrypted_tx_in = test_transaction_out.to_encrypted_data(address).unwrap(); + + store_encrypted_data(encrypted_tx_in).unwrap(); + } + + #[test] + fn test_get_transactions_out() { + test_store_tx_out(); + test_store_view_session(); + + let test_transaction_id = AleoID::, TX_PREFIX>::from_str( + "at1zux4zw83dayxtndd58skuy7qq7xg0d6ez86ak9zlqh2zru4kgggqjys70g", + ) + .unwrap(); + + let test_transaction_out = TransactionPointer::new( + Some("Test_User".to_string()), + Some(test_transaction_id), + TransactionState::Confirmed, + Some(100u32), + Some("test_program_id".to_string()), + Some("test_function_id".to_string()), + vec![], + vec![], + Local::now(), + Some(Local::now() + chrono::Duration::seconds(40)), + None, + EventTypeCommon::Send, + None, + None, + None, + ); + + let transactions_out = get_transactions_exec::().unwrap(); + + assert_eq!(vec![test_transaction_out], transactions_out) + } + + #[test] + fn test_get_unconfirmed_and_failed_transaction_ids() { + VIEWSESSION.set_view_session("AViewKey1jXL3nQ7ax6ft9qshgtTn8nXrkKNFjSBdbnjueFW5f2Gj"); + + let transactions_out = get_unconfirmed_and_failed_transaction_ids::().unwrap(); + + println!("{:?}", transactions_out); + } + + #[test] + fn test_get_transaction_ids_from_date() { + VIEWSESSION.set_view_session("AViewKey1jXL3nQ7ax6ft9qshgtTn8nXrkKNFjSBdbnjueFW5f2Gj"); + + let date = Local::now(); + let a_day_ago = date - chrono::Duration::days(1); + + let transactions_out = get_tx_ids_from_date::(a_day_ago).unwrap(); + + println!("{:?}", transactions_out); + } +} diff --git a/src-tauri/src/services/local_storage/storage_api/transition.rs b/src-tauri/src/services/local_storage/storage_api/transition.rs new file mode 100644 index 00000000..8a8c6ff5 --- /dev/null +++ b/src-tauri/src/services/local_storage/storage_api/transition.rs @@ -0,0 +1,123 @@ +use snarkvm::prelude::{Address, Network}; + +use crate::models::pointers::transition::TransitionPointer; +use crate::services::local_storage::{ + encrypted_data::{get_encrypted_data_by_flavour, store_encrypted_data}, + session::view::VIEWSESSION, +}; + +use avail_common::{ + errors::AvailResult, + models::encrypted_data::{EncryptedData, EncryptedDataTypeCommon}, +}; + +/* -- Transitions -- */ + +pub fn get_transitions() -> AvailResult>> { + let encrypted_transitions = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transition)?; + + decrypt_transitions(encrypted_transitions) +} + +//TODO - Test how long this takes with multiple transactions to decrypt +pub fn get_transition_ids() -> AvailResult> { + let transitions = get_transitions::()?; + + // TODO - Get transitions from transition_pointers, TransactionPointer and TransactionMessage + let tx_ids = transitions + .iter() + .map(|transition| transition.id.to_string()) + .collect::>(); + + Ok(tx_ids) +} + +pub fn decrypt_transitions( + encrypted_transitions: Vec, +) -> AvailResult>> { + let v_key = VIEWSESSION.get_instance::()?; + + let transitions = encrypted_transitions + .iter() + .map(|x| { + let encrypted_data = x.to_enrypted_struct::()?; + + let tx_in: TransitionPointer = encrypted_data.decrypt(v_key)?; + + Ok(tx_in) + }) + .collect::>>>()?; + + Ok(transitions) +} + +fn encrypt_and_store_transitions( + transitions: Vec>, + address: Address, +) -> AvailResult> { + let encrypted_transitions = transitions + .iter() + .map(|transition| { + let encrypted_data = transition.to_encrypted_data(address)?; + + store_encrypted_data(encrypted_data.clone())?; + + Ok(encrypted_data) + }) + .collect::>>()?; + + Ok(encrypted_transitions) +} + +#[cfg(test)] +mod transitions_storage_api_tests { + use super::*; + use snarkvm::{ + prelude::{Field, Group, Identifier, Input, Output, ProgramID, Testnet3, Transition}, + utilities::{TestRng, Uniform}, + }; + use std::str::FromStr; + + #[test] + fn test_get_transitions() { + let transitions = get_transitions::().unwrap(); + + print!("Transitions \n {:?}", transitions) + } + #[test] + fn test_get_transitions_ids() { + let transition_ids = get_transition_ids::().unwrap(); + + print!("Transition IDs \n {:?}", transition_ids) + } + + fn initialise_test_transition() -> Transition { + let mut rng = TestRng::default(); + + let field = Field::::new(Uniform::rand(&mut rng)); + let program_identifier = Identifier::::from_str("test_program_id").unwrap(); + let domain_identifier = Identifier::::from_str("aleo").unwrap(); + + let program_id = + ProgramID::::try_from((program_identifier, domain_identifier)).unwrap(); + + let function_name = Identifier::::from_str("test").unwrap(); + + let input = Input::::Constant(field, None); + let output = Output::::Constant(field, None); + + let tpk = Group::::new(Uniform::rand(&mut rng)); + let tcm = Field::::new(Uniform::rand(&mut rng)); + let transition = Transition::::new( + program_id, + function_name, + vec![input], + vec![output], + tpk, + tcm, + ) + .unwrap(); + + transition + } +} diff --git a/src-tauri/src/services/local_storage/tokens.rs b/src-tauri/src/services/local_storage/tokens.rs new file mode 100644 index 00000000..abbeaec0 --- /dev/null +++ b/src-tauri/src/services/local_storage/tokens.rs @@ -0,0 +1,328 @@ +use crate::models::storage::persistent::PersistentStorage; +use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; +use snarkvm::prelude::*; + +pub fn init_tokens_table() -> AvailResult<()> { + let storage = PersistentStorage::new()?; + storage.execute_query( + "CREATE TABLE IF NOT EXISTS ARC20_tokens ( + token_name TEXT PRIMARY KEY, + program_id TEXT NOT NULL, + balance_ciphertext TEXT NOT NULL, + nonce TEXT NOT NULL + )", + )?; + Ok(()) +} + +pub fn drop_tokens_table() -> AvailResult<()> { + let storage = PersistentStorage::new()?; + match storage.execute_query("DROP TABLE IF EXISTS ARC20_tokens") { + Ok(r) => r, + Err(e) => match e.error_type { + AvailErrorType::NotFound => {} + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + e.internal_msg, + "Error deleting tokens table".to_string(), + )) + } + }, + }; + + Ok(()) +} + +pub fn init_token( + token_name: &str, + program_id: &str, + encryption_address: &str, + balance: &str, +) -> AvailResult<()> { + let storage = PersistentStorage::new()?; + + storage.execute_query( + "CREATE TABLE IF NOT EXISTS ARC20_tokens ( + token_name TEXT PRIMARY KEY, + program_id TEXT NOT NULL, + balance_ciphertext TEXT NOT NULL, + nonce TEXT NOT NULL + )", + )?; + + let rng = &mut rand::thread_rng(); + let scalar = Scalar::::rand(rng); + let nonce = N::g_scalar_multiply(&scalar); + + let plaintext = Plaintext::::from_str(balance)?; + let address = Address::::from_str(encryption_address)?; + let encrypted_balance = plaintext.encrypt(&address, scalar)?; + + storage.save( + vec![ + token_name.to_string(), + program_id.to_string(), + encrypted_balance.to_string(), + nonce.to_string(), + ], + "INSERT INTO ARC20_tokens (token_name, program_id, balance_ciphertext, nonce) VALUES (?1, ?2, ?3, ?4)" + .to_string(), + )?; + + Ok(()) +} + +pub fn add_balance( + token_name: &str, + balance: &str, + vk: ViewKey, +) -> AvailResult { + let storage = PersistentStorage::new()?; + let query = format!( + "SELECT balance_ciphertext, nonce FROM ARC20_tokens WHERE token_name='{}' ", + token_name + ); + let res = storage.get_all::(&query, 2)?; + match res.get(0) { + Some(old_encrypted_balance) => { + let nonce = Group::::from_str(res[0].get(1).unwrap())?; + let ciphertext = Ciphertext::::from_str(&old_encrypted_balance[0])?; + let old_balance_string = ciphertext.decrypt(vk, nonce)?.to_string(); + let old_balance = old_balance_string.trim_end_matches("u64").parse::()?; + + let temp_balance = balance.trim_end_matches("u64").parse::()?; + let new_balance = match old_balance.checked_add(temp_balance) { + Some(bal) => Ok(bal), + None => Err(AvailError::new( + AvailErrorType::InvalidData, + "err".to_string(), + "edd".to_string(), + )), + }?; + let rng = &mut rand::thread_rng(); + let scalar = Scalar::::rand(rng); + let nonce = N::g_scalar_multiply(&scalar); + let new_encrypted_balance = Plaintext::::encrypt( + &Plaintext::::from_str(&format!("{}u64", new_balance))?, + &vk.to_address(), + scalar, + )?; + storage.save( + vec![new_encrypted_balance.to_string(), nonce.to_string()], + format!("UPDATE ARC20_tokens SET balance_ciphertext = ?1, nonce = ?2 WHERE token_name='{}'", token_name), + )?; + Ok(new_balance.to_string()) + } + None => Err(AvailError::new( + AvailErrorType::LocalStorage, + "None_found".to_string(), + "Nonefound".to_string(), + )), + } +} + +pub fn subtract_balance( + token_name: &str, + balance: &str, + vk: ViewKey, +) -> AvailResult { + let storage = PersistentStorage::new()?; + let query = format!( + "SELECT balance_ciphertext, nonce FROM ARC20_tokens WHERE token_name='{}' ", + token_name + ); + let res = storage.get_all::(&query, 2)?; + match res.get(0) { + Some(old_encrypted_balance) => { + let nonce = res[0].get(1).unwrap(); + let old_balance_string = Ciphertext::::decrypt( + &Ciphertext::::from_str(&old_encrypted_balance[0])?, + vk, + Group::::from_str(nonce)?, + )? + .to_string(); + let old_balance = old_balance_string.trim_end_matches("u64").parse::()?; + + let temp_balance = balance.trim_end_matches("u64").parse::()?; + let new_balance = match old_balance.checked_sub(temp_balance) { + Some(bal) => Ok(bal), + None => Err(AvailError::new( + AvailErrorType::InvalidData, + "err".to_string(), + "edd".to_string(), + )), + }?; + let rng = &mut rand::thread_rng(); + let scalar = Scalar::::rand(rng); + let nonce = N::g_scalar_multiply(&scalar); + let new_encrypted_balance = Plaintext::::encrypt( + &Plaintext::::from_str(&format!("{}u64", new_balance))?, + &vk.to_address(), + scalar, + )?; + storage.save( + vec![new_encrypted_balance.to_string(), nonce.to_string()], + format!("UPDATE ARC20_tokens SET balance_ciphertext = ?1, nonce = ?2 WHERE token_name='{}'", token_name), + )?; + Ok(new_balance.to_string()) + } + None => Err(AvailError::new( + AvailErrorType::LocalStorage, + "None_found".to_string(), + "Nonefound".to_string(), + )), + } +} + +pub fn get_balance(token_name: &str, vk: ViewKey) -> AvailResult { + let storage = PersistentStorage::new()?; + let query = format!( + "SELECT balance_ciphertext, nonce FROM ARC20_tokens WHERE token_name='{}' ", + token_name + ); + let res = storage.get_all::(&query, 2)?; + match res.get(0) { + Some(old_encrypted_balance) => { + let nonce = res[0].get(1).unwrap(); + let old_balance_string = Ciphertext::::decrypt( + &Ciphertext::::from_str(&old_encrypted_balance[0])?, + vk, + Group::::from_str(nonce)?, + )? + .to_string(); + Ok(old_balance_string) + } + None => Ok("0u64".to_string()), + } +} // wrap this func and with only token id as param and vk is + +pub fn if_token_exists(token_name: &str) -> AvailResult { + let storage = PersistentStorage::new()?; + let query = format!( + "SELECT balance_ciphertext FROM ARC20_tokens WHERE token_name='{}'", + token_name + ); + // let res = ?; + match storage.get_all::(&query, 1) { + Ok(balance) => { + println!("====> {:?}", balance); + if balance.is_empty() { + Ok(false) + } else { + Ok(true) + } + } + Err(_) => Ok(false), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_program_id_for_token(token_name: &str) -> AvailResult { + let storage = PersistentStorage::new()?; + let query = format!( + "SELECT program_id FROM ARC20_tokens WHERE token_name='{}'", + token_name + ); + // let res = ?; + let res = storage.get_all::(&query, 1)?; + match res.get(0) { + Some(p_id) => Ok(p_id[0].clone()), + None => Ok("".to_string()), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_stored_tokens() -> AvailResult> { + let storage = PersistentStorage::new()?; + let query = "SELECT token_name FROM ARC20_tokens"; + let res = storage.get_all::(query, 1)?; + + println!("Token ids ====> {:?}", res); + + Ok(res.iter().map(|x| x[0].clone()).collect()) +} + +pub fn delete_tokens_table() -> AvailResult<()> { + let storage = PersistentStorage::new()?; + let query = "DROP TABLE ARC20_tokens"; + + match storage.execute_query(query) { + Ok(r) => r, + Err(e) => match e.error_type { + AvailErrorType::NotFound => {} + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + e.internal_msg, + "Error deleting tokens table".to_string(), + )) + } + }, + }; + + Ok(()) +} + +mod test_tokens { + use super::*; + + use crate::api::aleo_client::{setup_client, setup_local_client}; + use crate::models::event::Network as EventNetwork; + use avail_common::{aleo_tools::api::AleoAPIClient, models::constants::*}; + + #[test] + fn test_init() { + let api_client: AleoAPIClient = setup_client::().unwrap(); + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let vk = ViewKey::::try_from(pk).unwrap(); + let res = + init_token::("testnew111.record", "diff.aleo", TESTNET_ADDRESS, "100u64") + .unwrap(); + } + #[test] + fn test_pid() { + let api_client: AleoAPIClient = setup_client::().unwrap(); + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let vk = ViewKey::::try_from(pk).unwrap(); + let res = get_program_id_for_token("testnew111.record").unwrap(); + println!("{:?}", res); + } + #[test] + fn test_add_balance() { + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let vk = ViewKey::::try_from(pk).unwrap(); + let res = add_balance("test_token", "100u64", vk).unwrap(); + println!("{:?}", res); + } + + #[test] + fn test_subtract_balance() { + let api_client: AleoAPIClient = setup_client::().unwrap(); + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let vk = ViewKey::::try_from(pk).unwrap(); + let res = subtract_balance("token1", "100u64", vk).unwrap(); + println!("{:?}", res); + } + + #[test] + fn test_get_balance() { + let api_client: AleoAPIClient = setup_client::().unwrap(); + let pk = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); + //let vk = ViewKey::::try_from(pk).unwrap(); + + let vk = + ViewKey::::from_str("AViewKey1rWpxoch574dTmVu9zRovZ5UKyhZeBv9ftP2MkEy6TJRF") + .unwrap(); + + let res = get_balance("credits.record", vk).unwrap(); + println!("{:?}", res); + } + + #[test] + fn test_record_exists() { + let api_client: AleoAPIClient = setup_client::().unwrap(); + let res = if_token_exists("token_not_existing").unwrap(); + println!("{:?}", res); + } +} diff --git a/src-tauri/src/services/local_storage/utils.rs b/src-tauri/src/services/local_storage/utils.rs new file mode 100644 index 00000000..dfb4f867 --- /dev/null +++ b/src-tauri/src/services/local_storage/utils.rs @@ -0,0 +1,345 @@ +use std::str::FromStr; + +use crate::api::encrypted_data::delete_all_server_storage; +use crate::api::user::delete_user; +use crate::models::storage::encryption::{Keys, Keys::PrivateKey as PKey, Keys::ViewKey as VKey}; +use crate::models::storage::languages::Languages; +use crate::models::wallet::BetterAvailWallet; +use crate::services::local_storage::{ + encrypted_data::drop_encrypted_data_table, + persistent_storage::{delete_user_preferences, get_backup_flag, get_language, get_network}, + session::view::VIEWSESSION, + tokens::drop_tokens_table, +}; +use avail_common::models::constants::VIEW_KEY; +use snarkvm::prelude::{ + Ciphertext, Field, Identifier, Network, PrivateKey, Signature, Testnet3, ViewKey, +}; + +use crate::services::account::key_management::key_controller::{ + linuxKeyController, macKeyController, windowsKeyController, KeyController, +}; + +use avail_common::{ + aleo_tools::encryptor::Encryptor, + converters::messages::{field_to_fields, utf8_string_to_bits}, + errors::{AvailError, AvailErrorType, AvailResult}, + models::{constants::PRIVATE_KEY, network::SupportedNetworks}, +}; + +#[tauri::command(rename_all = "snake_case")] +pub fn get_private_key_tauri(password: Option) -> AvailResult { + let network = get_network()?; + + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + let key = get_private_key::(password)?; + Ok(key.to_string()) + } + _ => Err(AvailError::new( + AvailErrorType::Internal, + "Invalid network.".to_string(), + "Invalid network.".to_string(), + )), + } +} + +pub fn get_private_key(password: Option) -> AvailResult> { + let key_manager = { + #[cfg(target_os = "macos")] + { + macKeyController + } + #[cfg(target_os = "windows")] + { + windowsKeyController + } + #[cfg(target_os = "linux")] + { + linuxKeyController + } + }; + + let key = match password { + Some(password) => key_manager.read_key(Some(&password), PRIVATE_KEY), + None => key_manager.read_key(None, PRIVATE_KEY), + }?; + + let private_key = match key { + Keys::PrivateKey(p) => p, + Keys::ViewKey(_) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Invalid key type.".to_string(), + "Invalid key type.".to_string(), + )) + } + }; + + Ok(private_key) +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_seed_phrase(password: Option) -> AvailResult { + let network = get_network()?; + + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + let key_manager = { + #[cfg(target_os = "macos")] + { + macKeyController + } + #[cfg(target_os = "windows")] + { + windowsKeyController + } + #[cfg(target_os = "linux")] + { + linuxKeyController + } + }; + + let val: Identifier = Identifier::::from_str("test")?; + + let seed_phrase = match password { + Some(password) => key_manager.read_phrase(&password, val), + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Password is required.".to_string(), + "Password is required.".to_string(), + )) + } + }?; + + Ok(seed_phrase) + } + } +} + +/// Get viewing key from keychain, also used as local authentication +#[tauri::command(rename_all = "snake_case")] +pub fn get_view_key_tauri(password: Option) -> AvailResult { + let network = get_network()?; + + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + let key = get_view_key::(password)?; + VIEWSESSION.set_view_session(&key.to_string())?; + + Ok(key.to_string()) + } + } +} + +pub fn get_view_key(password: Option) -> AvailResult> { + let key_manager = { + #[cfg(target_os = "macos")] + { + macKeyController + } + #[cfg(target_os = "windows")] + { + windowsKeyController + } + #[cfg(target_os = "linux")] + { + linuxKeyController + } + }; + + let key = match password { + Some(password) => key_manager.read_key(Some(&password), VIEW_KEY), + None => key_manager.read_key(None, VIEW_KEY), + }?; + + let viewing_key = match key { + Keys::ViewKey(v) => v, + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Invalid key type.".to_string(), + "Invalid key type.".to_string(), + )) + } + }; + + Ok(viewing_key) +} + +pub fn encrypt_with_password( + password: &str, + key: &Keys, +) -> AvailResult> { + match key { + PKey(private_key) => Ok(Encryptor::encrypt_private_key_with_secret( + &private_key, + password, + )?), + VKey(view_key) => Ok(Encryptor::encrypt_view_key_with_secret( + &view_key, password, + )?), + } +} + +pub fn encrypt_private_key_with_password( + password: &str, + private_key: &PrivateKey, +) -> AvailResult> { + Ok(Encryptor::encrypt_private_key_with_secret( + private_key, + password, + )?) +} + +pub fn encrypt_view_key_with_password( + password: &str, + view_key: &ViewKey, +) -> AvailResult> { + Ok(Encryptor::encrypt_view_key_with_secret(view_key, password)?) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn delete_util(password: &str) -> AvailResult { + let backup = get_backup_flag()?; + + let key_manager = { + #[cfg(target_os = "macos")] + { + macKeyController + } + #[cfg(target_os = "windows")] + { + windowsKeyController + } + #[cfg(target_os = "linux")] + { + linuxKeyController + } + }; + + let val: Identifier = Identifier::::from_str("test")?; + + match key_manager.delete_key(Some(password), val) { + Ok(_) => {} + Err(e) => {} + }; + + // delete encrypted data + drop_encrypted_data_table()?; + + // delete user preferences + delete_user_preferences()?; + + // delete tokens + drop_tokens_table()?; + + // if backup delete server side storage + if backup { + delete_all_server_storage().await?; + } + + // delete server user + delete_user().await?; + + Ok("Deleted.".to_string()) +} + +#[tauri::command(rename_all = "snake_case")] +pub fn delete_local_for_recovery(password: &str) -> AvailResult<()> { + let key_manager = { + #[cfg(target_os = "macos")] + { + macKeyController + } + #[cfg(target_os = "windows")] + { + windowsKeyController + } + #[cfg(target_os = "linux")] + { + linuxKeyController + } + }; + + let val: Identifier = Identifier::::from_str("test")?; + + match key_manager.delete_key(Some(password), val) { + Ok(_) => {} + Err(e) => {} + }; + + // delete encrypted data + drop_encrypted_data_table()?; + + // delete user preferences + delete_user_preferences()?; + + // delete tokens + drop_tokens_table()?; + + Ok(()) +} + +// Sign any string +pub fn sign_message( + message: &str, + password: Option, +) -> AvailResult<(Signature, Field)> { + let key = get_private_key::(password)?; + + let v_key = ViewKey::::try_from(key)?; + VIEWSESSION.set_view_session(&v_key.to_string())?; + + let rng = &mut rand::thread_rng(); + + let msg = utf8_string_to_bits(message); + let msg_field = N::hash_bhp512(&msg)?; + let msg = field_to_fields(&msg_field)?; + + let signature = key.sign(&msg, rng)?; + + Ok((signature, msg_field)) +} + +// Sign any string with provided private key +pub fn sign_message_w_key( + message: &str, + private_key: &PrivateKey, +) -> AvailResult<(Signature, Field)> { + let rng = &mut rand::thread_rng(); + + let msg = utf8_string_to_bits(message); + let msg_field = N::hash_bhp512(&msg)?; + let msg = field_to_fields(&msg_field)?; + + let signature = private_key.sign(&msg, rng)?; + + Ok((signature, msg_field)) +} + +mod test_utils { + use super::*; + use avail_common::models::constants::STRONG_PASSWORD; + use snarkvm::utilities::ToBytes; + + #[tokio::test] + async fn test_delete() { + delete_util(STRONG_PASSWORD).await.unwrap(); + } + + #[test] + fn test_several_pk_bytes() { + let pk1 = PrivateKey::::new(&mut rand::thread_rng()).unwrap(); + + let pk2 = PrivateKey::::new(&mut rand::thread_rng()).unwrap(); + + let pk1_bytes = pk1.to_bytes_le().unwrap(); + + let pk2_bytes = pk2.to_bytes_le().unwrap(); + + print!("PK1: {:?}", pk1_bytes); + print!("PK2 {:?}", pk2_bytes); + } +} diff --git a/src-tauri/src/services/record_handling.rs b/src-tauri/src/services/record_handling.rs new file mode 100644 index 00000000..60543f36 --- /dev/null +++ b/src-tauri/src/services/record_handling.rs @@ -0,0 +1,5 @@ +pub mod decrypt_transition; +pub mod records; +pub mod sync; +pub mod transfer; +pub mod utils; diff --git a/src-tauri/src/services/record_handling/decrypt_transition.rs b/src-tauri/src/services/record_handling/decrypt_transition.rs new file mode 100644 index 00000000..15aaa625 --- /dev/null +++ b/src-tauri/src/services/record_handling/decrypt_transition.rs @@ -0,0 +1,668 @@ +use std::str::FromStr; + +use chrono::{DateTime, Local}; +use snarkvm::{ + prelude::{ + Ciphertext, Field, Group, Identifier, Input, Literal, Network, Output, Plaintext, + ProgramID, ToBits, Transition, ViewKey, U16, + }, + utilities::Uniform, +}; + +use super::utils::output_to_record_pointer; +use crate::{ + models::pointers::{ + record::AvailRecord, + transition::{TransitionPointer, TransitionType}, + }, + models::wallet_connect::records::{GetRecordsRequest, RecordFilterType, RecordsFilter}, + services::local_storage::{ + encrypted_data::store_encrypted_data, + storage_api::records::{ + get_record_pointers, get_record_pointers_ids, update_record_spent_local, + }, + }, +}; +use avail_common::{errors::AvailResult, models::encrypted_data::EncryptedData}; + +pub struct DecryptTransition {} + +impl DecryptTransition { + // Used to check if the user has executed the transition + pub fn owns_transition( + view_key: ViewKey, + tpk: Group, + tcm: Field, + ) -> AvailResult { + let scalar = *view_key; + let tvk = (tpk * scalar).to_x_coordinate(); + + //error == "Could not create transition commitment" + let tcm_derived = N::hash_psd2(&[tvk])?; + + Ok(tcm == tcm_derived) + } + + // used to check if user owns input or output ciphertext + // if it is an input + pub fn decrypt_ciphertext( + view_key: ViewKey, + ciphertext_str: &str, + tpk_str: &str, + program_id: &str, + function_name_str: &str, + index: usize, + ) -> AvailResult { + let tpk = Group::::from_str(tpk_str)?; + + //error == "Could not deserialize program_id" + let program_id = ProgramID::::from_str(program_id)?; + + //error == "Could not deserialize function name" + let function_name = Identifier::::from_str(function_name_str)?; + + let scalar = *view_key; + let tvk = (tpk * scalar).to_x_coordinate(); + + //error == "Could not create function id" + let function_id = N::hash_bhp1024( + &( + U16::::new(N::ID), + program_id.name(), + program_id.network(), + function_name, + ) + .to_bits_le(), + )?; + + let index_field = Field::from_u16(u16::try_from(index)?); + + //error == "Could not create ciphertext view key" + let ciphertext_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; + + //error == "Could not deserialize ciphertext" + let ciphertext = Ciphertext::::from_str(ciphertext_str)?; + + //error == "Could not decrypt ciphertext" + let plaintext = ciphertext.decrypt_symmetric(ciphertext_view_key)?; + + Ok(plaintext.to_string()) + } + + // Checks if the user sent inputs in the transiton or received ouputs from the transition + pub fn check_inputs_outputs_inclusion( + view_key: ViewKey, + transition: Transition, + transaction_id: N::TransactionID, + timestamp: DateTime, + block_height: u32, + message: Option, + from: Option, + ) -> AvailResult<(Vec>, Vec, Vec)> { + let address = view_key.to_address(); + let transition_id = transition.id(); + let function_name = transition.function_name().to_string(); + let program_id = transition.program_id().to_string(); + let scalar = *view_key; + let tvk = (*transition.tpk() * scalar).to_x_coordinate(); + + //filter + let filter = RecordsFilter::new( + vec![transition.program_id().to_string()], + None, + RecordFilterType::Unspent, + None, + ); + let get_records_request = GetRecordsRequest::new(None, Some(filter), None); + let (stored_record_pointers, ids) = get_record_pointers::(get_records_request)?; + + let function_id = N::hash_bhp1024( + &( + U16::::new(N::ID), + transition.program_id().name(), + transition.program_id().network(), + transition.function_name(), + ) + .to_bits_le(), + )?; + + let mut decrypted_inputs: Vec> = vec![]; + let mut encrypted_input_transition_pointers: Vec = vec![]; + let mut spent_input_ids: Vec = vec![]; + + let mut decrypted_outputs: Vec> = vec![]; + let mut encrypted_output_transition_pointers: Vec = vec![]; + + let mut record_pointers: Vec> = vec![]; + let mut amount = None; + + //check inputs + for (index, input) in transition.inputs().iter().enumerate() { + if let Input::Record(_id, _checksum) = input { + // spent records should be handled here + let input_tag = match input.tag() { + Some(tag) => tag, + None => continue, + }; + + for (record_pointer, id) in stored_record_pointers.iter().zip(ids.iter()) { + if &record_pointer.tag()? == input_tag { + update_record_spent_local::(id, true)?; + spent_input_ids.push(id.to_string()); + println!("================> INSIDE Input::Record"); + + let mock_input = + Input::::Public(Uniform::rand(&mut rand::thread_rng()), None); + decrypted_inputs.push(mock_input.clone()); + } + } + } else if let Input::Public(_plaintext_hash, Some(plaintext)) = input { + let plaintext_address = Plaintext::::Literal( + Literal::from_str(&address.to_string())?, + once_cell::sync::OnceCell::new(), + ); + + if plaintext == &plaintext_address { + let rng = &mut rand::thread_rng(); + + amount = find_amount_from_public_transfer(transition.inputs()); + + println!("Amount {:?}", amount); + //function is some public transfer to this address thus it is an Output tx + let mock_output = Output::::Public(Uniform::rand(rng), None); + + decrypted_outputs.push(mock_output); + } + } + } + + //check outputs + let num_inputs = transition.inputs().len(); + for (index, output) in transition.outputs().iter().enumerate() { + if let Output::Private(id, ciphertext_option) = output { + if let Some(ciphertext) = ciphertext_option { + let index_field = Field::from_u16(u16::try_from(num_inputs + index)?); + let output_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; + let plaintext = match ciphertext.decrypt_symmetric(output_view_key) { + Ok(plaintext) => plaintext, + Err(_) => { + continue; + } + }; + println!( + "================> INSIDE Output::Private ----> PlainText -- {:?}", + plaintext + ); + let output = Output::Public(*id, Some(plaintext)); + decrypted_outputs.push(output.clone()); + } + } else if let Output::Record(_id, _checksum, _record) = output { + let (record_pointer, found_amount) = output_to_record_pointer( + transaction_id, + transition_id.to_owned(), + transition.function_name(), + transition.program_id(), + output, + block_height, + view_key, + index, + )?; + + // println!("================> INSIDE Output::Record"); + match record_pointer { + Some(record_pointer) => { + record_pointers.push(record_pointer.clone()); + + let encrypted_record_pointer = record_pointer.to_encrypted_data(address)?; + store_encrypted_data(encrypted_record_pointer)?; + + decrypted_outputs.push(output.clone()); + println!("================> INSIDE record_pointer"); + } + None => continue, + } + + if let Some(found_amount) = found_amount { + //parse found amount from u64 + let found_amount_trimmed = found_amount.trim_end_matches("u64"); + let found_amount = found_amount_trimmed.parse::()? as f64 / 1000000.0; + + amount = Some(found_amount); + } + } + } + + if !decrypted_inputs.is_empty() { + // form transition pointer + let transition_pointer = TransitionPointer::new( + transition_id.to_owned(), + transaction_id, + program_id.clone(), + function_name.clone(), + timestamp, + TransitionType::Input, + message.clone(), + from.clone(), + amount, + block_height, + ); + println!("================> INSIDE !decrypted_inputs.is_empty()"); + + let encrypted_transition_pointer = transition_pointer.to_encrypted_data(address)?; + store_encrypted_data(encrypted_transition_pointer.clone())?; + encrypted_input_transition_pointers.push(encrypted_transition_pointer); + } + + if !decrypted_outputs.is_empty() { + // form transition pointer + let transition_pointer = TransitionPointer::new( + transition_id.to_owned(), + transaction_id, + program_id, + function_name, + timestamp, + TransitionType::Output, + message, + from, + amount, + block_height, + ); + println!("================> INSIDE !decrypted_outputs.is_empty()"); + let encrypted_transition_pointer = transition_pointer.to_encrypted_data(address)?; + store_encrypted_data(encrypted_transition_pointer.clone())?; + + encrypted_output_transition_pointers.push(encrypted_transition_pointer); + } + + // combine encrypted transition pointers + let mut encrypted_transition_pointers: Vec = vec![]; + encrypted_transition_pointers.append(&mut encrypted_input_transition_pointers); + encrypted_transition_pointers.append(&mut encrypted_output_transition_pointers); + + Ok(( + record_pointers, + encrypted_transition_pointers, + spent_input_ids, + )) + } + + pub fn decrypt_transition( + view_key: ViewKey, + transition_str: &str, + ) -> AvailResult { + let transition: Transition = serde_json::from_str(transition_str)?; + + let scalar = *view_key; + let tvk = (*transition.tpk() * scalar).to_x_coordinate(); + + let function_id = N::hash_bhp1024( + &( + U16::::new(N::ID), + transition.program_id().name(), + transition.program_id().network(), + transition.function_name(), + ) + .to_bits_le(), + )?; + + let mut decrypted_inputs: Vec> = vec![]; + let mut decrypted_outputs: Vec> = vec![]; + + for (index, input) in transition.inputs().iter().enumerate() { + if let Input::Private(id, Some(ciphertext)) = input { + let index_field = Field::from_u16(u16::try_from(index)?); + let input_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; + let plaintext = ciphertext.decrypt_symmetric(input_view_key)?; + decrypted_inputs.push(Input::Public(*id, Some(plaintext))); + } else { + decrypted_inputs.push(input.clone()); + } + } + + let num_inputs = transition.inputs().len(); + for (index, output) in transition.outputs().iter().enumerate() { + if let Output::Private(id, Some(ciphertext)) = output { + let index_field = Field::from_u16(u16::try_from(num_inputs + index)?); + let output_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; + let plaintext = ciphertext.decrypt_symmetric(output_view_key)?; + decrypted_outputs.push(Output::Public(*id, Some(plaintext))); + } else { + decrypted_outputs.push(output.clone()); + } + } + + let decrypted_transition = Transition::::new( + *transition.program_id(), + *transition.function_name(), + decrypted_inputs, + decrypted_outputs, + *transition.tpk(), + *transition.tcm(), + )?; + + let transition_output = serde_json::to_string(&decrypted_transition)?; + + Ok(transition_output) + } + + pub fn decrypt_inputs_outputs( + view_key: ViewKey, + transition: &Transition, + ) -> AvailResult<(Vec, Vec)> { + let scalar = *view_key; + let tvk = (*transition.tpk() * scalar).to_x_coordinate(); + + let function_id = N::hash_bhp1024( + &( + U16::::new(N::ID), + transition.program_id().name(), + transition.program_id().network(), + transition.function_name(), + ) + .to_bits_le(), + )?; + + let mut decrypted_inputs: Vec = vec![]; + let mut decrypted_outputs: Vec = vec![]; + + let (stored_record_pointers, _ids) = get_record_pointers_ids::()?; + + for (index, input) in transition.inputs().iter().enumerate() { + if let Input::Private(_id, ciphertext_option) = input { + if let Some(ciphertext) = ciphertext_option { + let index_field = Field::from_u16(u16::try_from(index)?); + + let input_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; + let input_str = match ciphertext.decrypt_symmetric(input_view_key) { + Ok(plaintext) => plaintext.to_string(), + Err(_) => ciphertext.to_string(), + }; + + decrypted_inputs.push(input_str); + } else { + decrypted_inputs.push(input.to_string()); + } + } else if let Input::Record(_serial_number, tag) = input { + for record_pointer in stored_record_pointers.iter() { + if &record_pointer.tag()? == tag { + let record = record_pointer.to_record()?; + decrypted_inputs.push(record.to_string()); + } + } + } else if let Input::Public(_plaintext_hash, plaintext) = input { + if let Some(plaintext) = plaintext { + decrypted_inputs.push(plaintext.to_string()); + } + } else if let Input::Constant(_plaintext_hash, plaintext) = input { + if let Some(plaintext) = plaintext { + decrypted_inputs.push(plaintext.to_string()); + } + } else if let Input::ExternalRecord(_input_commitent) = input { + //handle external record input + } + } + + let num_inputs = transition.inputs().len(); + for (index, output) in transition.outputs().iter().enumerate() { + if let Output::Private(_id, ciphertext_option) = output { + if let Some(ciphertext) = ciphertext_option { + let index_field = Field::from_u16(u16::try_from(num_inputs + index)?); + + let output_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; + let output_str = match ciphertext.decrypt_symmetric(output_view_key) { + Ok(plaintext) => plaintext.to_string(), + Err(_) => ciphertext.to_string(), + }; + + decrypted_outputs.push(output_str); + } else { + decrypted_outputs.push(output.to_string()); + } + } else if let Output::Record(_commitment, _checksum, ciphertext) = output { + match ciphertext { + Some(ciphertext) => { + // do i own this output? + let record = match ciphertext.decrypt(&view_key) { + Ok(plaintext) => plaintext.to_string(), + Err(_) => ciphertext.to_string(), + }; + + decrypted_outputs.push(record); + } + None => { + decrypted_outputs.push(output.to_string()); + } + } + } else if let Output::Public(_plaintext_hash, plaintext) = output { + if let Some(_plaintext) = plaintext { + decrypted_outputs.push(output.to_string()); + } + } else if let Output::Future(_future_hash, future) = output { + if let Some(future) = future { + decrypted_outputs.push(future.to_string()); + } + } else if let Output::Constant(_plaintext_hash, plaintext) = output { + if let Some(plaintext) = plaintext { + decrypted_outputs.push(plaintext.to_string()); + } + } else { + decrypted_outputs.push(output.to_string()); + } + } + Ok((decrypted_inputs, decrypted_outputs)) + } +} + +pub fn find_amount_from_public_transfer(inputs: &[Input]) -> Option { + for input in inputs { + print!("{:?}", input); + if let Input::Public(_plaintext_hash, Some(Plaintext::Literal(Literal::U64(amount), _))) = + input + { + print!("{:?}", amount); + return Some(**amount as f64 / 1000000.0); + } + } + None +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use snarkvm::console::network::Testnet3; + use snarkvm::prelude::PrivateKey; + + use super::*; + use avail_common::models::constants::*; + + const VIEW_KEY: &str = "AViewKey1nPQW8P83ajkMBHQwYjbUfjGHVSkBQ5wctpJJmQvW1SyZ"; + const INCORRECT_VIEW_KEY: &str = "AViewKey1o8Hqq4tVbVMeeGtkEGUR7ULghFN8j89sqNQKYRZfe21u"; + const TRANSITION_VIEW_KEY: &str = "AViewKey1mSnpFFC8Mj4fXbK5YiWgZ3mjiV8CxA79bYNa8ymUpTrw"; + const TRANSITION: &str = r#" + { + "id": "as1pe954nkrsz4ztq7tphfug0cxtk4t0v5nnh885llkxufkckc0pcqq64fdjh", + "program": "credits.aleo", + "function": "transfer", + "inputs": [ + { + "type": "record", + "id": "7627242362896255517779759121644670167065542804779447008052019369271498021878field", + "tag": "7326825649979738473754819542510294000608550604334299567498630301585328020355field" + }, + { + "type": "private", + "id": "5890350227539634203276798567594921209939645071583932668707733854543695228358field", + "value": "ciphertext1qgqz2ypza9srfjnncjzz3hegltwmk0y348ufmklcuqwep2u9wnsqwqkrgx49dn0x78uqypznmyv8r80zwkte9rkfucv7fk4hw7w5s86dzyjmktp7" + }, + { + "type": "private", + "id": "3523824429192332435402492789955521910058950257573863610460494169456702420796field", + "value": "ciphertext1qyqfuz7006rcq9utzdsthdxqv4ra59u58wuggcacv44ka5uv7gyjcrsfh5xwh" + } + ], + "outputs": [ + { + "type": "record", + "id": "8375863992930925508608168893083821026035462437311607208725719081756051927038field", + "checksum": "327996249778261324588393772992776501551729208590293775377741829891566277743field", + "value": "record1qyqsqv0te3n9fws54jjywmrp36lc8l5gxgzyc9anjk30qsf7h45nfvgpqyxx66trwfhkxun9v35hguerqqpqzq8hd7es9dptx8l6ldn7u536g3hefvl03e6ztrufgk97ekf0us6azgl65lhfgcm4jf7fua2pcc2asy7r46rzv7eefvc8yrs39sgadue3zkl3emg" + }, + { + "type": "record", + "id": "3831168224702324801478452706121992429555677457517630037556628292830553507758field", + "checksum": "104402939347002555939092140274082734465350067270030368157770539944634402431field", + "value": "record1qyqspsy0qghu8wqmf8wq2w4ccqqg8zsgxc3ge2znf4uklh8tutq2swgqqyxx66trwfhkxun9v35hguerqqpqzq9c6u30j7srax79wdvdqt2ytpne4vyvae6z9fq85rs09nj2f72uqm0kn9tx5t3znnj7hrqffzdcquacgyrqdfuuum2km7wvxcmy258svvkjzsh" + } + ], + "proof": "proof1qqqqzqqqqqqqqqqqjgn70r0h5xcsysua8uve5wk400ash3ry6dwr3jjmeft5dmmql03ju0memtrwzppfsyl9x25v6svgrled6hd4s2887yz6wdde7fmv3kwlrdjx8kpvzq5asy02sljyc87ya7me3h5nkh3davwqklw6m2qzszt850x7jq0kt45zghwah6kalw7ufdh2v83jcrcwcpcwwa0m44sestdagm0z7hqe20zlfszva22kfqgpvnj9mavgqw2v5rmeeyz8hmn2j29npkvgteg0447zh6c097tx4dr2vmu2n5ts67xqu83058sjus3srrdgcypql8mymv7rhg580m5gckc4vnwjm2a53vg9sgqmyahs4fhmm0t0atyp9gjvflpt76d2nnsaqyqntm08rmtg0mwzajy2lpyfgq0r0gwq6pqcraty4623uyrzz8036np4clx3ak54qdlfamprav0chq95d696hsy4sdpsfphxuzq5mmehl0pjgk3f7wuvtjshz9dyrnrcwggnmjdqw965fmnjhlxv86ddruqj3cur9r38g2v4evaf2n5clr0844aek7j2gvz4zgshfddlkrg92wzk4yfwdjrwuvmpv77ss2f3efypelqu8sjp23fk93ygdads9lqtz8ghggdy5uhe9j7cyrg2ug4ghww9vvfljk2rgk04sfm23n8j474gzsmzz0nptrtdqmr2afddp5acssa5twxlcpf6vcghssrdan52wrykz5evryzvarw0xj9y0zf2ddarqxqfv2rcjfey9ur7tmaeh2qvqv8z9ggg8vtajql6vj2vuw5shmxsjahcq2ve7m3m3s8a30vy0qx47u263g77hz448mxug4r99vfgkpggv7rysklv0e9l40nt20uvnkuepeftgqwlz7t436z93fpq5qadxsr2tl93t87czw68h6nsglh9xxnenasa2f68vl7pvqahnjlyatcvzyytqxrglvgax9525hwvn939k9jtxzjeh97chr07qgvsp6f007c3p7hdca6cm7ss7wmdrefehzzpj4rpj30cnu2rhdce35ku3y640avsxlujsxnfs69g32q3nlqe7tlcka9zkmeurxx3fcq054sseehe2kqjr2tfdwmgfzgj28vynw4nxq54pvmpgkj53asfnt25yz250lmx0vzqyqqqqqqqqqqq9c4hem5wef967dqy4spcypsr8kwhnmxp35zlrdgq6rwejyqej2l2h6w2lnc7ttw2qxlj8shfju5czqwrcnaj00ky0yc98jck2rk43upw4gzxk6l866n0mh68q0vjalg0qd7tvlu4an04s3u799u28vct6wwm2gn0r5lpcv5jttds6ffw6ykkq6g42yvlam6zreceeqwqz25mrqqqqqppqwa5", + "tpk": "853764860907185272244987221391264508066723405990098126446569313951469774602group", + "tcm": "2890501131780933954363007654088502278361631362478553633880506988907453958068field" + } + "#; + const TRANSITION2: &str = r#" + { + "id":"au12llfye62hrxva7kdtk6c8qjff5w06pys77qaf74yvk8nm36pcvzqzhnyqk", + "program":"credits.aleo", + "function":"transfer_public_to_private", + "inputs":[ + { + "type":"private", + "id":"8304400100965833495700876350325817857909709976454835525511070424468112487393field", + "value":"ciphertext1qgqqra9lu5kxlcyantu9m62y64q6a6lqnpwnjhw7sfhzpvfs3xfrkzvd3f8y43ayxvg06m0jdy5mygzkq5xtzhesnaevv2sevtrr8tlups2ylg7q" + }, + { + "type":"public", + "id":"4284736765818567156746053297849217056635200819021601944769636535729298276732field", + "value":"10000u64" + } + ], + "outputs":[ + { + "type":"record", + "id":"7700798280026244642782503068152162345162841409942906121174875714371266381229field", + "checksum":"6815669942399919593565610266251968344648606815539211826018363024847516584293field", + "value":"record1qyqsqyqj75z6agymcp8n3zc3vdt79flrvmkntw3x3ns9r62cajs28rs9qyxx66trwfhkxun9v35hguerqqpqzq82x8jygs6uu3xv5vvsfqmhxwp0mgd6cp94s9tltctq6k7kfk5xp6f70g4ehp4cu3uky7gt7dsfe5lxgg9v8f89zfqhckxdy4fjlt3sgeectyv"}, + { + "type":"future", + "id":"7497616154742727853190695963847945689716274231039404007173109580428445795806field", + "value":"{\n program_id: credits.aleo,\n function_name: transfer_public_to_private,\n arguments: [\n aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px,\n 10000u64\n ]\n}"}], + "tpk":"7536197841680445770427840516566211501284881266835565366311996370053681646595group", + "tcm":"5280795820292733910634681057195416067603461129653774341851374878700562172179field" + } + "#; + + #[test] + fn test_decrypt_transition() { + let private_key = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let view_key = ViewKey::::try_from(private_key).unwrap(); + + let decrypted_transition_str = + DecryptTransition::decrypt_transition(view_key, TRANSITION2).unwrap(); + + let decrypted_transition: Transition = + serde_json::from_str(&decrypted_transition_str.clone()).unwrap(); + + println!("Decrypted Transition {:?}", decrypted_transition); + let public_input = decrypted_transition + .inputs() + .into_iter() + .skip(1) + .next() + .unwrap(); + /* + if let Input::Public(_id, plaintext_option) = public_input { + let plaintext = plaintext_option.as_ref().unwrap(); + assert_eq!( + plaintext.to_string(), + "aleo146dx5e4nssf49t0aq9qljk474kqxk848tl05m8w84vc0jqa30spqf4me04" + ); + } else { + panic!("Expected public input"); + } + */ + // let public_output = decrypted_transition.outputs().into_iter().next().unwrap(); + + // if let Output::Public(_id, plaintext_option) = public_output { + // let plaintext = plaintext_option.as_ref().unwrap(); + // assert_eq!(plaintext.to_string(), "100000000u64"); + // } else { + // panic!("Expected public output"); + // } + } + + fn test_decrypt_ciphertext_input() { + let view_key = ViewKey::::from_str(VIEW_KEY).unwrap(); + + // Try decrypting private input + let plaintext = DecryptTransition::decrypt_ciphertext( + view_key, + "ciphertext1qyq2786j69kjqmwz7lk9cn3glyq2w34j6zhlvxum6u9xkfk76hmd2rgg34kev", + "3681563105640905751787370687361466941855498391730203508101562167054325552256group", + "helloworld.aleo", + "main", + 1, + ) + .unwrap(); + + assert_eq!(plaintext, "2u32"); + } + + #[test] + fn test_decrypt_ciphertext_output() { + let view_key = ViewKey::::from_str(VIEW_KEY).unwrap(); + + // Try decrypting private output + let plaintext = DecryptTransition::decrypt_ciphertext( + view_key, + "ciphertext1qyqw68078jwlvz6v2wynue3g3dndyv0ydqutlmn99sfashquhkf52zql6xu7r", + "3681563105640905751787370687361466941855498391730203508101562167054325552256group", + "helloworld.aleo", + "main", + 2, + ) + .unwrap(); + + assert_eq!(plaintext, "3u32"); + } + + #[test] + fn test_owns_transition_true() { + let view_key = ViewKey::::from_str(VIEW_KEY).unwrap(); + + let owns_transition = DecryptTransition::owns_transition( + view_key, + Group::::from_str( + "3681563105640905751787370687361466941855498391730203508101562167054325552256group", + ) + .unwrap(), + Field::::from_str( + "3205548165782039452146864733009325261935114902820697593223360259711032449007field", + ) + .unwrap(), + ) + .unwrap(); + + assert!(owns_transition); + } + + #[test] + fn test_owns_transition_false() { + let view_key = ViewKey::::from_str(INCORRECT_VIEW_KEY).unwrap(); + + let owns_transition = DecryptTransition::owns_transition( + view_key, + Group::::from_str( + "3681563105640905751787370687361466941855498391730203508101562167054325552256group", + ) + .unwrap(), + Field::::from_str( + "3205548165782039452146864733009325261935114902820697593223360259711032449007field", + ) + .unwrap(), + ) + .unwrap(); + + assert!(!owns_transition); + } +} diff --git a/src-tauri/src/services/record_handling/docs.md b/src-tauri/src/services/record_handling/docs.md new file mode 100644 index 00000000..371f40d6 --- /dev/null +++ b/src-tauri/src/services/record_handling/docs.md @@ -0,0 +1,4 @@ +# Notes on Record Handling + +## The tag system +`tag` construction, the `tag` is not stored with the record as tag but can be computed via `N::hash_psd2(&[sk_tag, commitment])` as we do where `sk_tag` can only be derived from your `view_key` , and then the tag is stored on chain when this record is spent so you can literally query a block for all the tags it stores and these would be all the tags of records spent within that block. But you cannot check if a specific record has been spent without the viewing key. diff --git a/src-tauri/src/services/record_handling/records.rs b/src-tauri/src/services/record_handling/records.rs new file mode 100644 index 00000000..f59c734d --- /dev/null +++ b/src-tauri/src/services/record_handling/records.rs @@ -0,0 +1,800 @@ +use chrono::Local; +use snarkvm::{ + console::program::Itertools, + prelude::{ConfirmedTransaction, Network, Plaintext, Record}, +}; +use std::ops::Sub; +use tauri::{Manager, Window}; + +use crate::{ + api::aleo_client::{setup_client, setup_local_client}, + helpers::utils::get_timestamp_from_i64, + models::wallet_connect::records::{GetRecordsRequest, RecordFilterType, RecordsFilter}, + services::{ + local_storage::{ + encrypted_data::{ + handle_block_scan_failure, update_encrypted_transaction_confirmed_by_id, + update_encrypted_transaction_state_by_id, + }, + persistent_storage::{get_address_string, update_last_sync}, + session::view::VIEWSESSION, + storage_api::{ + deployment::{find_encrypt_store_deployments, get_deployment_pointer}, + records::{get_record_pointers, get_record_pointers_for_record_type}, + transaction::{ + check_unconfirmed_transactions, get_transaction_pointer, get_tx_ids_from_date, + get_unconfirmed_and_failed_transaction_ids, + }, + }, + }, + record_handling::utils::{ + get_executed_transitions, handle_deployment_confirmed, handle_deployment_rejection, + handle_transaction_confirmed, handle_transaction_rejection, input_spent_check, + sync_transaction, transition_to_record_pointer, + }, + }, +}; + +use avail_common::{ + aleo_tools::program_manager::Credits, + errors::{AvailError, AvailErrorType, AvailResult}, + models::encrypted_data::{EncryptedData, RecordTypeCommon, TransactionState}, +}; + +/// Scans the blockchain for new records, distills record pointers, transition pointer and tags, and returns them +pub fn get_records( + last_sync: u32, + height: u32, + window: Option, +) -> AvailResult { + let view_key = VIEWSESSION.get_instance::()?; + let address = view_key.to_address(); + + let api_client = setup_client::()?; + + let step_size = 49; + + let latest_height = height; + + let last_sync_block = api_client.get_block(last_sync)?; + let last_sync_timestamp = get_timestamp_from_i64(last_sync_block.timestamp())?; + + // checks if unconfirmed transactions have expired and updates their state to failed + check_unconfirmed_transactions::()?; + + let stored_transaction_ids = get_tx_ids_from_date::(last_sync_timestamp)?; + + println!("Stored transaction ids: {:?}", stored_transaction_ids); + + let unconfirmed_and_failed_ids = get_unconfirmed_and_failed_transaction_ids::()?; + + println!( + "Unconfirmed and failed ids: {:?}", + unconfirmed_and_failed_ids + ); + + let unconfirmed_and_failed_transaction_ids = unconfirmed_and_failed_ids + .iter() + .map(|(id, _)| *id) + .collect::>(); + + let stored_transaction_ids = stored_transaction_ids + .iter() + .filter(|id| !unconfirmed_and_failed_transaction_ids.contains(id)) + .cloned() + .collect_vec(); + + println!( + "Stored transaction ids without unconfirmed and failed: {:?}", + stored_transaction_ids + ); + + let mut end_height = last_sync.saturating_add(step_size); + let mut start_height = last_sync; + + if end_height > latest_height { + end_height = latest_height; + } + + let mut found_flag = false; + + for _ in (last_sync..latest_height).step_by(step_size as usize) { + let mut blocks = api_client.get_blocks(start_height, end_height)?; + + for block in blocks { + // Check for deployment transactions + let transactions = block.transactions(); + let timestamp = get_timestamp_from_i64(block.clone().timestamp())?; + let height = block.height(); + + match find_encrypt_store_deployments( + transactions, + height, + timestamp, + address, + stored_transaction_ids.clone(), + ) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error scanning deployment transactions.".to_string(), + )); + } + } + + for transaction in transactions.iter() { + let transaction_id = transaction.id(); + + let unconfirmed_transaction_id = match transaction.to_unconfirmed_transaction_id() { + Ok(id) => id, + Err(_) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::SnarkVm, + "Error getting unconfirmed transaction id".to_string(), + "Issue getting unconfirmed transaction id".to_string(), + )); + } + }; + + if stored_transaction_ids.contains(&transaction_id) + || stored_transaction_ids.contains(&unconfirmed_transaction_id) + { + continue; + } + + if let Some((tx_id, pointer_id)) = + unconfirmed_and_failed_ids.iter().find(|(tx_id, _)| { + tx_id == &transaction_id || tx_id == &unconfirmed_transaction_id + }) + { + let inner_tx = transaction.transaction(); + let fee = match inner_tx.fee_amount() { + Ok(fee) => *fee as f64 / 1000000.0, + Err(_) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::SnarkVm, + "Error calculating fee".to_string(), + "Issue calculating fee".to_string(), + )); + } + }; + + if let ConfirmedTransaction::::AcceptedExecute(_, _, _) = transaction { + let executed_transitions = + match get_executed_transitions::(inner_tx, height) { + Ok(transitions) => transitions, + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::SnarkVm, + e.to_string(), + "Error getting executed transitions".to_string(), + )); + } + }; + + match handle_transaction_confirmed( + pointer_id.as_str(), + *tx_id, + executed_transitions, + height, + timestamp, + Some(fee), + address, + ) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error handling confirmed transaction".to_string(), + )); + } + }; + + continue; + } else if let ConfirmedTransaction::::AcceptedDeploy(_, _, _) = transaction { + if let Some(fee_transition) = transaction.fee_transition() { + let transition = fee_transition.transition(); + + match input_spent_check(transition, true) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error checking spent input".to_string(), + )); + } + }; + + match transition_to_record_pointer( + *tx_id, + transition.clone(), + height, + view_key, + ) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error finding records from transition".to_string(), + )); + } + }; + } + + match handle_deployment_confirmed( + pointer_id.as_str(), + *tx_id, + height, + Some(fee), + address, + ) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error handling confirmed deployment".to_string(), + )); + } + }; + + continue; + } else if let ConfirmedTransaction::::RejectedDeploy(_, fee_tx, _, _) = + transaction + { + let deployment_pointer = + match get_deployment_pointer::(pointer_id.as_str()) { + Ok(pointer) => pointer, + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error getting deployment pointer".to_string(), + )); + } + }; + + if let Some(fee_transition) = fee_tx.fee_transition() { + let transition = fee_transition.transition(); + + match input_spent_check(transition, true) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error checking spent input".to_string(), + )); + } + }; + + match transition_to_record_pointer( + *tx_id, + transition.clone(), + height, + view_key, + ) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error finding records from transition".to_string(), + )); + } + }; + } + + match handle_deployment_rejection( + deployment_pointer, + pointer_id.as_str(), + *tx_id, + height, + Some(fee), + address, + ) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error handling rejected deployment".to_string(), + )); + } + }; + + continue; + } else if let ConfirmedTransaction::::RejectedExecute( + _, + fee_tx, + rejected_tx, + _, + ) = transaction + { + let transaction_pointer = + match get_transaction_pointer::(pointer_id.as_str()) { + Ok(pointer) => pointer, + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error getting transaction pointer".to_string(), + )); + } + }; + + if let Some(fee_transition) = fee_tx.fee_transition() { + let transition = fee_transition.transition(); + + match input_spent_check(transition, true) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error checking spent input".to_string(), + )); + } + }; + + match transition_to_record_pointer( + *tx_id, + transition.clone(), + height, + view_key, + ) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error finding records from transition".to_string(), + )); + } + }; + } + + if let Some(rejected_execution) = rejected_tx.execution() { + match handle_transaction_rejection( + transaction_pointer, + pointer_id.as_str(), + Some(rejected_execution.clone()), + Some(*tx_id), + height, + Some(fee), + address, + ) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error handling rejected transaction".to_string(), + )); + } + }; + + continue; + } + + match handle_transaction_rejection( + transaction_pointer, + pointer_id.as_str(), + None, + Some(*tx_id), + height, + Some(fee), + address, + ) { + Ok(_) => {} + Err(e) => { + handle_block_scan_failure::(height)?; + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error handling rejected transaction".to_string(), + )); + } + }; + + continue; + } + continue; + } + + let (_, _, _, bool_flag) = + match sync_transaction::(transaction, height, timestamp, None, None) { + Ok(transaction_result) => transaction_result, + Err(e) => { + match handle_block_scan_failure::(height) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error syncing transaction".to_string(), + )); + } + } + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error syncing transaction".to_string(), + )); + } + }; + + if !found_flag { + found_flag = bool_flag; + } + } + + match update_last_sync(height) { + Ok(_) => { + println!("Synced {}", height); + } + Err(e) => { + match handle_block_scan_failure::(height) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error syncing transaction".to_string(), + )); + } + } + + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error updating last synced block height".to_string(), + )); + } + }; + } + + let percentage = (((end_height - last_sync) as f32 / (latest_height - last_sync) as f32) + * 10000 as f32) + .round() + / 100.0; + + let percentage = if percentage > 100.0 { + 100.0 + } else { + percentage + }; + + println!("{}% of blocks scanned", percentage); + + // update progress bar + if let Some(window) = window.clone() { + match window.emit("scan_progress", percentage) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error updating progress bar".to_string(), + )); + } + }; + } + + // Search in reverse order from the latest block to the earliest block + start_height = end_height + 1; + end_height = start_height.saturating_add(step_size); + if end_height > latest_height { + end_height = latest_height; + }; + } + + Ok(found_flag) +} + +/// Fetches an aleo credits record to spend +pub fn find_aleo_credits_record_to_spend( + amount: &u64, + previous: Vec, +) -> AvailResult<(Record>, String, String)> { + let address = get_address_string()?; + let (record_pointers, encrypted_record_ids) = + get_record_pointers_for_record_type::(RecordTypeCommon::AleoCredits, &address)?; + + let mut iter = 0; + let mut balance_counter = 0u64; + + for record in record_pointers.iter() { + if record.metadata.spent { + iter += 1; + continue; + } + if previous.clone().contains(&record.metadata.nonce) { + iter += 1; + continue; + } + + let aleo_record = record.to_record()?; + let record_amount = aleo_record.microcredits()?; + + if &record_amount >= amount { + return Ok(( + aleo_record, + record.pointer.commitment.clone(), + encrypted_record_ids[iter].clone(), + )); + } + + iter += 1; + balance_counter += record_amount; + } + + // TODO - implement join_n + if &balance_counter > amount { + return Err(AvailError::new( + AvailErrorType::Internal, + "Join aleo credit records to obtain a sufficient balance.".to_string(), + "Join aleo credit records to obtain a sufficient balance.".to_string(), + )); + } + + Err(AvailError::new( + AvailErrorType::Internal, + "Not enough balance".to_string(), + "Not enough balance".to_string(), + )) + + // find first record that satisfies the amount required +} + +pub fn find_tokens_to_spend( + asset_id: &str, + amount: &u64, + previous: Vec, +) -> AvailResult<(Record>, String, String)> { + let _address = get_address_string()?; + let program_id = format!("{}{}", asset_id, ".aleo"); + let record_name = format!("{}{}", asset_id, ".record"); + + let filter = RecordsFilter::new( + vec![program_id.to_string()], + None, + RecordFilterType::Unspent, + Some(record_name.to_string()), + ); + let get_records_request = GetRecordsRequest::new(None, Some(filter), None); + let (record_pointers, ids) = get_record_pointers::(get_records_request)?; + + let mut iter = 0; + let mut balance_counter = 0u64; + + for record in record_pointers.iter() { + if record.metadata.spent { + iter += 1; + continue; + } + if previous.clone().contains(&record.metadata.nonce) { + iter += 1; + continue; + } + + let aleo_record = record.to_record()?; + let record_amount = aleo_record.microcredits()?; + + if &record_amount >= amount { + return Ok(( + aleo_record, + record.pointer.commitment.clone(), + ids[iter].clone(), + )); + } + + iter += 1; + balance_counter += record_amount; + } + + // TODO - implement join_n + if &balance_counter > amount { + return Err(AvailError::new( + AvailErrorType::Internal, + "Join token records to obtain a sufficient balance.".to_string(), + "Join token records to obtain a sufficient balance.".to_string(), + )); + } + + Err(AvailError::new( + AvailErrorType::Internal, + "Not enough balance".to_string(), + "Not enough balance".to_string(), + )) + + // find first record that satisfies the amount required +} + +///Joins two records together +/// TODO - Join n records to meet amount x +/* +async fn join_records( + pk: PrivateKey, + amount: u64, + token: &str, +) -> AvailResult { + let fee = 10000u64; + + let fee_record = find_aleo_credits_record_to_spend::(fee, vec![])?; + + // TODO - iteratively find records until amount is satisfied + + + let inputs: Vec> = vec![Value::Record(input_record), Value::Record(input2_record)]; + + let api_client = AleoAPIClient::::local_testnet3("3030"); + let mut program_manager = + ProgramManager::::new(Some(pk), None, Some(api_client), None).unwrap(); + + //calculate estimate + + let join_execution = program_manager.execute_program( + "credits.aleo", + "join", + inputs.iter(), + fee, + fee_record, + None, + )?; + + update_identifier_status(fee_commitment, &fee_id).await?; + update_identifier_status(input_commitment, &input_id).await?; + update_identifier_status(input2_commitment, &input2_id).await?; + + //check tx block, normal post tx procedure + Ok(join_execution) +} +*/ + +///Splits a record into two records +/* +async fn split_records( + pk: PrivateKey, + amount: u64, + token: &str, +) -> AvailResult { + let fee = 10000u64; + + let fee_record = find_aleo_credits_record_to_spend::(fee, vec![])?; + + let input_record = find_aleo_credits_record_to_spend::(amount, vec![])?; + + let inputs: Vec> = vec![Value::Record(input_record)]; + + let api_client = AleoAPIClient::::local_testnet3("3030"); + let mut program_manager = + ProgramManager::::new(Some(pk), None, Some(api_client), None).unwrap(); + + let split_execution = program_manager.execute_program( + "credits.aleo", + "split", + inputs.iter(), + fee, + fee_record, + None, + )?; + + //TODO - How to get commitment from record + + update_identifier_status(fee_record.to_commitment(program_id, record_name), &fee_id).await?; + update_identifier_status(input_commitment, &input_id).await?; + + Ok(split_execution) +} +*/ + +#[cfg(test)] +mod record_handling_test { + use super::*; + use crate::services::local_storage::persistent_storage::get_last_sync; + use snarkvm::prelude::{AleoID, Field, Testnet3}; + use std::str::FromStr; + + #[test] + fn test_get_transaction() { + let start = 500527u32; + let end = 500531u32; + + let api_client = setup_client::().unwrap(); + + let blocks = api_client.get_blocks(start, end).unwrap(); + + let tx_id = &AleoID::, 29793>::from_str( + "at1w8t8pkc9xuf2p05gp9fanxpx0h53jmpguc07ja34s3jm905v65gss306rr", + ); + + for block in blocks { + let transactions = block.transactions(); + + match tx_id { + Ok(tx_id) => { + let tx = transactions.get(tx_id); + let info = match tx { + Some(tx) => tx, + None => { + println!("tx not found"); + continue; + } + }; + println!("info: {:?}", info); + } + Err(e) => { + print!("{}", e.to_string()) + } + } + } + } + + /* + #[test] + fn test_nova() { + let _res = get_nova_records::(372243).unwrap(); + + println!("res: {:?}", _res); + } + */ + + #[test] + fn test_get_records() { + let api_client = setup_client::().unwrap(); + + let latest_height = api_client.latest_height().unwrap(); + let last_sync = get_last_sync().unwrap(); + + let _res = get_records::(last_sync, latest_height, None).unwrap(); + + println!("res: {:?}", _res); + } + + #[test] + fn find_aleo_credits_record_to_spend_test() { + let _res = find_aleo_credits_record_to_spend::(&10000, vec![]).unwrap(); + + println!("res: {:?}", _res); + } +} diff --git a/src-tauri/src/services/record_handling/sync.rs b/src-tauri/src/services/record_handling/sync.rs new file mode 100644 index 00000000..8c646dc4 --- /dev/null +++ b/src-tauri/src/services/record_handling/sync.rs @@ -0,0 +1,805 @@ +use snarkvm::prelude::*; +use tauri::Window; +use uuid::Uuid; + +use crate::{ + api::{ + aleo_client::{setup_client, setup_local_client}, + encrypted_data::{ + delete_invalid_transactions_in, get_new_transaction_messages, post_encrypted_data, + synced, + }, + }, + helpers::utils::get_timestamp_from_i64_utc, + models::event::TxScanResponse, + models::pointers::message::TransactionMessage, + services::local_storage::{ + encrypted_data::{ + get_encrypted_data_to_backup, get_encrypted_data_to_update, + update_encrypted_data_synced_on_by_id, + }, + storage_api::records::{encrypt_and_store_records, update_records_spent_backup}, + }, +}; + +use std::str::FromStr; + +use avail_common::{ + errors::{AvailError, AvailErrorType, AvailResult}, + models::{encrypted_data::EncryptedData, network::SupportedNetworks}, +}; + +use crate::services::local_storage::persistent_storage::{ + get_address, get_backup_flag, get_last_backup_sync, get_last_sync, get_network, + update_last_backup_sync, +}; + +use super::{records::get_records, utils::sync_transaction}; + +/// processes transactions into record and transition pointers and stores them +fn process_transaction( + transaction_message: &TransactionMessage, + address: Address, + id: Uuid, +) -> AvailResult<(Vec, Vec, Option)> { + let (transaction, timestamp) = transaction_message.verify()?; + + if let Some(transaction) = transaction { + println!("Transaction verified"); + let (_, record_pointers, encrypted_transitions, _) = sync_transaction( + &transaction, + transaction_message.confirmed_height(), + timestamp, + transaction_message.message(), + Some(transaction_message.from()), + )?; + println!("{:?}", record_pointers); + let encrypted_records = encrypt_and_store_records(record_pointers, address)?; + Ok((encrypted_records, encrypted_transitions, None)) + } else { + println!("Transaction failed verification"); + Ok((vec![], vec![], Some(id))) + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn txs_sync() -> AvailResult { + let network = get_network()?; + + let transactions = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => txs_sync_raw::().await?, + _ => txs_sync_raw::().await?, //SupportedNetworks::Devnet => txs_sync_raw::().await?, + //SupportedNetworks::Mainnet => txs_sync_raw::().await?, + }; + + Ok(transactions) +} + +/// syncs transactions sent to user by another avail user +pub async fn txs_sync_raw() -> AvailResult { + let api_client = setup_client::()?; + + let backup = get_backup_flag()?; + + let address = get_address::()?; + let latest_height = api_client.latest_height()?; + + let (txs_in, ids) = get_new_transaction_messages::().await?; + + println!("Transactions In: {:?}", txs_in); + + if txs_in == vec![] { + let res = TxScanResponse { + txs: false, + block_height: latest_height, + }; + return Ok(res); + } + + let mut records_n_transitions_to_post = txs_in + .iter() + .zip(ids.iter()) + .map(|(tx, id)| { + let (encrypted_records, encrypted_transitions, invalid_tx) = + process_transaction(tx, address, *id)?; + Ok((encrypted_records, encrypted_transitions, invalid_tx)) + }) + .collect::, Vec, Option)>>>()?; + + if backup { + // separate records and transitions + let records_to_post = records_n_transitions_to_post + .iter_mut() + .flat_map(|(records, _, _)| records.clone()) + .collect::>(); + + let transitions_to_post = records_n_transitions_to_post + .iter_mut() + .flat_map(|(_, transitions, _)| transitions.clone()) + .collect::>(); + + let invalid_ids = records_n_transitions_to_post + .iter_mut() + .filter_map(|(_, _, invalid_id)| *invalid_id) + .collect::>(); + + let encrypted_record_ids = post_encrypted_data(records_to_post).await?; + let encrypted_transition_ids = post_encrypted_data(transitions_to_post).await?; + + encrypted_record_ids + .iter() + .map(|id| update_encrypted_data_synced_on_by_id(id)) + .collect::>>()?; + + encrypted_transition_ids + .iter() + .map(|id| update_encrypted_data_synced_on_by_id(id)) + .collect::>>()?; + + let ids_to_sync = ids + .iter() + .filter(|id| !invalid_ids.contains(id)) + .copied() + .collect::>(); + + synced(ids_to_sync).await?; + delete_invalid_transactions_in(invalid_ids).await?; + } else { + //NOTE - delete encrypted messages (The name may be misleading, but this is just to clear the encrypted transaction messages sent after they are received.) + delete_invalid_transactions_in(ids).await?; + } + + let res = TxScanResponse::new(true, latest_height); + Ok(res) + + // TODO - Check if the records were spent through another platform in the meantime by taking the min block height, getting all the tags and checking the records found against them. +} + +// NOTE - Production, passes window as parameter +///scans all blocks from last sync to cater for transitions, new records created +#[tauri::command(rename_all = "snake_case")] +pub async fn blocks_sync(height: u32, window: Window) -> AvailResult { + let network = get_network()?; + let last_sync = get_last_sync()?; + + print!("From Last Sync: {:?} to height: {:?}", last_sync, height); + + let task = tokio::spawn(async move { + let found_flag = match SupportedNetworks::from_str(network.as_str())? { + SupportedNetworks::Testnet3 => { + get_records::(last_sync, height, Some(window))? + } + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Invalid Network".to_string(), + "Invalid Network".to_string(), + )); + } + }; + + Ok(found_flag) + }); + + let result = task.await; + + let found_flag = match result { + Ok(res) => res?, + Err(_) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error scanning Aleo blockchain".to_string(), + "Error scanning Aleo blockchain".to_string(), + )); + } + }; + + print!("Scan Complete"); + + Ok(found_flag) +} + +// TODO - Handle splitting the payload if it maxes deserialization limit. +/// Backs up unsynced encrypted data to the server +#[tauri::command(rename_all = "snake_case")] +pub async fn sync_backup() -> AvailResult<()> { + let network = get_network()?; + let backup = get_backup_flag()?; + + if backup { + let last_backup_sync = get_last_backup_sync()?; + + /* Handle spent updates first */ + let encrypted_data_to_update = get_encrypted_data_to_update(last_backup_sync)?; + + let ids_to_update = encrypted_data_to_update + .iter() + .filter_map(|data| data.id) + .map(|id| id.to_string()) + .collect::>(); + + // post spent updates + match SupportedNetworks::from_str(network.as_str())? { + SupportedNetworks::Testnet3 => { + update_records_spent_backup::(ids_to_update).await? + } + _ => update_records_spent_backup::(ids_to_update).await?, + }; + + /* Handle posting new found encrypted data */ + let encrypted_data = get_encrypted_data_to_backup(last_backup_sync)?; + + println!("Encrypted Data: {:?}", encrypted_data); + + let ids = post_encrypted_data(encrypted_data).await?; + + ids.iter() + .map(|id| update_encrypted_data_synced_on_by_id(id)) + .collect::>>()?; + + let last_sync = get_last_sync()?; + + // get timestamp from block + let api_client = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => setup_client::(), + _ => setup_client::(), + }; + + let block = api_client?.get_block(last_sync)?; + let timestamp = get_timestamp_from_i64_utc(block.timestamp())?; + + update_last_backup_sync(timestamp) + } else { + Err(AvailError::new( + AvailErrorType::Internal, + "Backup not enabled, go to settings to enable it.".to_string(), + "Backup not enabled, go to settings to enable it.".to_string(), + )) + } +} + +pub async fn blocks_sync_test(height: u32) -> AvailResult { + let network = get_network()?; + let last_sync = get_last_sync()?; + + print!("From Last Sync: {:?} to height: {:?}", last_sync, height); + + let task = tokio::spawn(async move { + let found_flag = match SupportedNetworks::from_str(network.as_str())? { + SupportedNetworks::Testnet3 => get_records::(last_sync, height, None)?, + _ => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Invalid Network".to_string(), + "Invalid Network".to_string(), + )); + } + }; + + Ok(found_flag) + }); + + let result = task.await; + + let found_flag = match result { + Ok(res) => res?, + Err(_) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error scanning Aleo blockchain".to_string(), + "Error scanning Aleo blockchain".to_string(), + )); + } + }; + + print!("Scan Complete {}", found_flag); + + Ok(found_flag) +} + +#[cfg(test)] +mod test { + use super::*; + + use crate::api::encrypted_data::delete_all_server_storage; + use crate::api::user::delete_user; + use crate::models::{storage::languages::Languages, transfer::TransferRequest}; + use crate::services::account::generation::import_wallet; + use crate::{ + models::pointers::transaction::TransactionPointer, + services::{ + account::key_management::key_controller::KeyController, + authentication::session::get_session_after_creation, + local_storage::{ + encrypted_data::{ + drop_encrypted_data_table, get_encrypted_data_by_flavour, + initialize_encrypted_data_table, + }, + persistent_storage::{ + delete_user_preferences, initial_user_preferences, update_address, + update_last_sync, + }, + session::view::VIEWSESSION, + storage_api::transaction::decrypt_transactions_exec, + }, + record_handling::{records::find_aleo_credits_record_to_spend, transfer::transfer_raw}, + }, + }; + + use avail_common::{ + aleo_tools::program_manager::{ProgramManager, TransferType}, + models::constants::*, + }; + + #[cfg(target_os = "linux")] + use crate::services::account::key_management::key_controller::linuxKeyController; + #[cfg(target_os = "macos")] + use crate::services::account::key_management::key_controller::macKeyController; + #[cfg(target_os = "windows")] + use crate::services::account::key_management::key_controller::windowsKeyController; + + use snarkvm::prelude::{AleoID, Field, FromStr, PrivateKey, Testnet3, ToBytes, ViewKey}; + + fn test_setup_prerequisites() { + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let view_key = ViewKey::::try_from(&pk).unwrap(); + + drop_encrypted_data_table().unwrap(); + + delete_user_preferences().unwrap(); + // initialize the user preferences + initial_user_preferences( + false, + None, + None, + false, + false, + view_key.to_address().to_string(), + Languages::English, + ) + .unwrap(); + initialize_encrypted_data_table().unwrap(); + + VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); + } + #[tokio::test] + async fn test_blocks_scan() { + //NOTE - Don't forget to change OS depending on what you testing on -default should be linux + + /* -- Has to be called here cause has to await-- */ + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let ext = Identifier::::from_str("test").unwrap(); + + let key_controller = { + #[cfg(target_os = "linux")] + { + linuxKeyController {} + } + + #[cfg(target_os = "macos")] + { + macKeyController {} + } + + #[cfg(target_os = "windows")] + { + windowsKeyController {} + } + }; + + let vk = ViewKey::::try_from(&pk).unwrap(); + + delete_user_preferences().unwrap(); + initial_user_preferences( + false, + None, + None, + false, + true, + vk.to_address().to_string(), + Languages::English, + ) + .unwrap(); + + get_session_after_creation(&pk).await.unwrap(); + delete_user().await.unwrap(); + + key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + //delete_all_server_storage().await.unwrap(); + drop_encrypted_data_table().unwrap(); + + delete_user_preferences().unwrap(); + // initialize the user preferences + + import_wallet( + None, + STRONG_PASSWORD.to_string(), + false, + &pk.to_string(), + false, + Languages::English, + ) + .await + .unwrap(); + + let fee = 4000000u64; + let amount = 100000u64; + let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); + let asset_id = "credits".to_string(); + + let request = TransferRequest::new( + recipient_address.to_string(), + amount, + Some("Public to Private Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::Public, + false, + fee, + asset_id, + ); + + transfer_raw::(request, None).await.unwrap(); + + let recipient_view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY).unwrap(); + + VIEWSESSION + .set_view_session(&recipient_view_key.to_string()) + .unwrap(); + + update_address(&recipient_address.to_string()).unwrap(); + + tokio::time::sleep(tokio::time::Duration::from_secs(45)).await; + + let api_client = setup_client::().unwrap(); + + let latest_height = api_client.latest_height().unwrap(); + + blocks_sync_test(latest_height).await.unwrap(); + + //sync_backup().await.unwrap(); + } + + #[tokio::test] + async fn test_scan() { + test_setup_prerequisites(); + + let api_client = setup_client::().unwrap(); + + let latest_height = api_client.latest_height().unwrap(); + blocks_sync_test(latest_height).await.unwrap(); + } + + // this will fail when using the same program name with the same node instance or live network + #[tokio::test] + async fn test_deployment_scan() { + /* prepare record for fee */ + //NOTE - Don't forget to change OS depending on what you testing on -default should be linux + + /* -- Has to be called here cause has to await-- */ + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let ext = Identifier::::from_str("test").unwrap(); + + let key_controller = { + #[cfg(target_os = "linux")] + { + linuxKeyController {} + } + + #[cfg(target_os = "macos")] + { + macKeyController {} + } + + #[cfg(target_os = "windows")] + { + windowsKeyController {} + } + }; + + key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + delete_all_server_storage().await.unwrap(); + drop_encrypted_data_table().unwrap(); + + delete_user_preferences().unwrap(); + // initialize the user preferences + + import_wallet( + Some("Satoshi".to_string()), + STRONG_PASSWORD.to_string(), + false, + &pk.to_string(), + false, + Languages::English, + ) + .await + .unwrap(); + + let fee = 4000000u64; + let amount = 100000u64; + let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); + let asset_id = "credits".to_string(); + + let request = TransferRequest::new( + recipient_address.to_string(), + amount, + Some("Public to Private Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::PublicToPrivate, + false, + fee, + asset_id, + ); + + transfer_raw::(request, None).await.unwrap(); + + /* --Setup Done-- */ + + let recipient_view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY).unwrap(); + let vk_bytes = recipient_view_key.to_bytes_le().unwrap(); + + VIEWSESSION + .set_view_session(&recipient_view_key.to_string()) + .unwrap(); + + let _res = txs_sync().await.unwrap(); + + let (string, program) = Program::::parse( + r" +program ftesting.aleo; + +mapping store: +key as u32.public; +value as u32.public; + +function compute: +input r0 as u32.private; +add r0 r0 into r1; +output r1 as u32.public;", + ) + .unwrap(); + assert!( + string.is_empty(), + "Parser did not consume all of the string: '{string}'" + ); + + let pk2 = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); + + let api_client = setup_client::().unwrap(); + + let mut program_manager = + ProgramManager::::new(Some(pk2), None, Some(api_client.clone()), None) + .unwrap(); + + program_manager.add_program(&program).unwrap(); + + let (fee_record, _fee_commitment, _fee_id) = + find_aleo_credits_record_to_spend::(&(amount - 1000), vec![]).unwrap(); + + let _deployment = program_manager + .deploy_program(program.id(), 0u64, Some(fee_record), None) + .unwrap(); + + let latest_height1 = api_client.latest_height().unwrap(); + update_last_sync(latest_height1).unwrap(); + + // go to sleep for 2 minutes + tokio::time::sleep(tokio::time::Duration::from_secs(25)).await; + + let latest_height2 = api_client.latest_height().unwrap(); + blocks_sync_test(latest_height2).await.unwrap(); + } + + #[tokio::test] + async fn test_txs_scan() { + /* prepare record for fee */ + /* -- Has to be called here cause has to await-- */ + let pk = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); + let ext = Identifier::::from_str("test").unwrap(); + + let key_controller = { + #[cfg(target_os = "linux")] + { + linuxKeyController {} + } + + #[cfg(target_os = "macos")] + { + macKeyController {} + } + + #[cfg(target_os = "windows")] + { + windowsKeyController {} + } + }; + + match key_controller.delete_key(Some(STRONG_PASSWORD), ext) { + Ok(_) => println!("Key deleted"), + Err(e) => println!("Error deleting key: {:?}", e), + } + + drop_encrypted_data_table().unwrap(); + + delete_user_preferences().unwrap(); + // initialize the user preferences + + import_wallet( + Some("SatoshiXY".to_string()), + STRONG_PASSWORD.to_string(), + false, + &pk.to_string(), + false, + Languages::English, + ) + .await + .unwrap(); + + println!("Imported Successfully"); + + let fee = 300000u64; + let amount = 400000u64; + let recipient_address = Address::::from_str(TESTNET3_ADDRESS_2).unwrap(); + let asset_id = "credits".to_string(); + + let request = TransferRequest::new( + recipient_address.to_string(), + amount, + Some("Public to Private Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::PublicToPrivate, + false, + fee, + asset_id, + ); + + transfer_raw::(request, None).await.unwrap(); + + /* --Setup Done-- */ + + println!("Testing Complete transaction storage"); + let data = get_encrypted_data_by_flavour( + avail_common::models::encrypted_data::EncryptedDataTypeCommon::TransactionMessage, + ) + .unwrap(); + println!("{:?}\n", data); + let transactions = decrypt_transactions_exec::(data.clone()).unwrap(); + println!("{:?}\n", transactions); + + for data_p in data { + let event = TransactionPointer::::decrypt_to_event(data_p).unwrap(); + println!("{:?}", event); + } + + let recipient_view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY2).unwrap(); + let vk_bytes = recipient_view_key.to_bytes_le().unwrap(); + + VIEWSESSION + .set_view_session(&recipient_view_key.to_string()) + .unwrap(); + update_address(&recipient_address.to_string()).unwrap(); + + let _res = txs_sync().await.unwrap(); + + println!("res: {:?}", _res); + } + + #[test] + fn test_process_transaction_failed_verification() { + let tx_id = &AleoID::, 29793>::from_str( + "at1w8t8pkc9xuf2p05gp9fanxpx0h53jmpguc07ja34s3jm905v65gss306rr", + ) + .unwrap(); + + let transition_id = &AleoID::, 30049>::from_str( + "au1w8t8pkc9xuf2p05gp9fanxpx0h53jmpguc07ja34s3jm905v65gss306rr", + ) + .unwrap(); + + let test_transaction_message = TransactionMessage::::new( + tx_id.clone(), + 0u32, + "Zack".to_string(), + Some("Hello".to_string()), + ); + + let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); + + let res = process_transaction(&test_transaction_message, address, Uuid::new_v4()).unwrap(); + + println!("res: {:?}", res); + } + + #[test] + fn test_get_latest_height() { + let api_client = setup_client::().unwrap(); + + let latest_height = api_client.latest_height().unwrap(); + println!("latest_height: {:?}", latest_height); + } + + #[tokio::test] + async fn test_transition_ownership() { + /* prepare record for fee */ + //NOTE - Don't forget to change OS depending on what you testing on -default should be linux + + /* -- Has to be called here cause has to await-- */ + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let ext = Identifier::::from_str("test").unwrap(); + + let key_controller = { + #[cfg(target_os = "linux")] + { + linuxKeyController {} + } + + #[cfg(target_os = "macos")] + { + macKeyController {} + } + + #[cfg(target_os = "windows")] + { + windowsKeyController {} + } + }; + + key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + drop_encrypted_data_table().unwrap(); + + delete_user_preferences().unwrap(); + // initialize the user preferences + + import_wallet( + Some("SatoshiX".to_string()), + STRONG_PASSWORD.to_string(), + false, + &pk.to_string(), + false, + Languages::English, + ) + .await + .unwrap(); + + let fee = 4000000u64; + let amount = 100000u64; + let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); + let asset_id = "credits".to_string(); + + let request = TransferRequest::new( + recipient_address.to_string(), + amount, + Some("Public to Private Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::PublicToPrivate, + false, + fee, + asset_id, + ); + + transfer_raw::(request, None).await.unwrap(); + + /* --Setup Done-- */ + + let recipient_view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY).unwrap(); + let vk_bytes = recipient_view_key.to_bytes_le().unwrap(); + + VIEWSESSION + .set_view_session(&recipient_view_key.to_string()) + .unwrap(); + + tokio::time::sleep(tokio::time::Duration::from_secs(30)).await; + + let api_client = setup_client::().unwrap(); + let latest_height2 = api_client.latest_height().unwrap(); + blocks_sync_test(latest_height2).await.unwrap(); + } +} diff --git a/src-tauri/src/services/record_handling/transfer.rs b/src-tauri/src/services/record_handling/transfer.rs new file mode 100644 index 00000000..01fd4c91 --- /dev/null +++ b/src-tauri/src/services/record_handling/transfer.rs @@ -0,0 +1,1413 @@ +use chrono::{DateTime, Local}; + +use dirs; +use snarkvm::{ledger::transactions::ConfirmedTransaction, prelude::*}; +use tauri::{Manager, Window}; +use tauri_plugin_http::reqwest; + +use std::fs; +use std::{ops::Add, str::FromStr}; +use tokio::time::{Duration, Instant}; + +use crate::api::aleo_client::setup_client; +use crate::services::local_storage::encrypted_data::update_encrypted_transaction_state_by_id; +use crate::{ + helpers::utils::get_timestamp_from_i64, + services::authentication::session::get_session_after_creation, + services::local_storage::storage_api::records::update_record_spent_local, +}; + +use crate::models::{pointers::transaction::TransactionPointer, transfer::TransferRequest}; + +use avail_common::{ + aleo_tools::program_manager::{ProgramManager, TransferType}, + errors::{AvailError, AvailErrorType, AvailResult}, + models::{ + encrypted_data::{EventTypeCommon, TransactionState}, + network::SupportedNetworks, + }, +}; + +use crate::services::local_storage::{ + persistent_storage::{get_address, get_network}, + session::password::PASS, + utils::get_private_key, +}; + +use super::records::*; +use super::utils::{get_address_from_recipient, handle_encrypted_storage_and_message}; + +/// Generic ARC20 token transfer function +#[tauri::command(rename_all = "snake_case")] +pub async fn transfer(request: TransferRequest, window: Window) -> AvailResult { + let network = get_network()?; + + let transfer_task_res = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + tokio::task::spawn_blocking(move || transfer_raw::(request, Some(window))) + .await? + } + _ => { + tokio::task::spawn_blocking(move || transfer_raw::(request, Some(window))) + .await? + } + } + .await?; + + PASS.extend_session()?; + + Ok(format!("Transaction '{}' Successful", transfer_task_res)) +} + +pub async fn transfer_raw( + request: TransferRequest, + window: Option, +) -> AvailResult { + match request.transfer_type() { + TransferType::Private => { + transfer_private_util::( + request.asset_id().as_str(), + request.amount(), + request.fee(), + request.fee_private(), + request.message().clone(), + request.recipient().as_str(), + request.password().clone(), + window, + ) + .await + } + TransferType::PublicToPrivate => { + transfer_public_to_private_util::( + request.asset_id().as_str(), + request.amount(), + request.fee(), + request.fee_private(), + request.message().clone(), + request.recipient().as_str(), + request.password().clone(), + window, + ) + .await + } + TransferType::PrivateToPublic => { + transfer_private_to_public_util::( + request.asset_id().as_str(), + request.amount(), + request.fee(), + request.fee_private(), + request.message().clone(), + request.recipient().as_str(), + request.password().clone(), + window, + ) + .await + } + TransferType::Public => { + transfer_public::( + request.asset_id().as_str(), + request.amount(), + request.fee(), + request.fee_private(), + request.message().clone(), + request.recipient().as_str(), + request.password().clone(), + window, + ) + .await + } + } +} + +/// Transfer tokens privately +async fn transfer_private_util( + asset_id: &str, + amount: &u64, + fee: &u64, + fee_private: &bool, + message: Option, + to: &str, + password: Option, + window: Option, +) -> AvailResult { + let api_client = setup_client::()?; + + let sender_address = get_address::()?; + + let private_key = get_private_key::(password)?; + + //extend session auth + let _session_task = get_session_after_creation::(&private_key).await?; + + let recipient = get_address_from_recipient::(to).await?; + let mut record_nonces: Vec = vec![]; + + let program_manager = + ProgramManager::::new(Some(private_key), None, Some(api_client.clone()), None).unwrap(); + + // get required records if private tx + let (token_record, _token_commitment, token_id) = + find_tokens_to_spend::(asset_id, amount, vec![])?; + let token_nonce = token_record.nonce().to_string(); + record_nonces.push(token_nonce); + + let (fee_record, _fee_commitment, fee_id) = match fee_private { + true => { + let (fee_record, _fee_commitment, fee_id) = + find_aleo_credits_record_to_spend::(fee, vec![])?; + let fee_nonce = fee_record.nonce().to_string(); + record_nonces.push(fee_nonce); + (Some(fee_record), Some(_fee_commitment), Some(fee_id)) + } + false => (None, None, None), + }; + + let program_id = format!("{}.aleo", asset_id); + + let mut pending_transaction = TransactionPointer::::new( + Some(to.to_string()), + None, + TransactionState::Processing, + None, + Some(program_id.clone()), + Some("transfer_private".to_string()), + vec![], + record_nonces, + Local::now(), + None, + message, + EventTypeCommon::Send, + Some(*amount as f64 / 1000000.0), + Some(*fee as f64 / 1000000.0), + None, + ); + + let pending_tx_id = pending_transaction.encrypt_and_store(sender_address)?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_tx_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + let amount = amount.to_owned(); + let fee = fee.to_owned(); + + // update spent states + update_record_spent_local::(&token_id, true)?; + if let Some(fee_id) = fee_id.clone() { + update_record_spent_local::(&fee_id, true)?; + } + + let transaction_id = match program_manager.transfer( + amount, + fee, + recipient, + TransferType::Private, + None, + Some(token_record), + fee_record.clone(), + &program_id, + ) { + Ok(tx_id) => tx_id, + Err(e) => { + println!("{:?}", e); + update_record_spent_local::(&token_id, false)?; + + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, false)?; + } + + pending_transaction.update_failed_transaction( + "Transaction execution failed, no records were spent.".to_string(), + ); + + let encrypted_failed_transaction = + pending_transaction.to_encrypted_data(sender_address)?; + + update_encrypted_transaction_state_by_id( + &pending_tx_id, + &encrypted_failed_transaction.ciphertext, + &encrypted_failed_transaction.nonce, + TransactionState::Failed, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_tx_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + return Err(AvailError::new( + AvailErrorType::Internal, + "Error transferring tokens".to_string(), + format!("Error transferring tokens: {:?}", e), + )); + } + }; + + let encrypted_message_task = tokio::spawn(async move { + handle_encrypted_storage_and_message( + transaction_id, + recipient, + &pending_tx_id, + Some(token_id), + fee_id, + false, + window, + ) + .await + }); + + match encrypted_message_task.await? { + Ok(_) => {} + Err(e) => return Err(e), + }; + + Ok(format!("Transaction Id {}", transaction_id)) +} + +/// Convert public tokens to private tokens +async fn transfer_public_to_private_util( + asset_id: &str, + amount: &u64, + fee: &u64, + fee_private: &bool, + message: Option, + to: &str, + password: Option, + window: Option, +) -> AvailResult { + let api_client = setup_client::()?; + let sender_address = get_address::()?; + let private_key = get_private_key::(password)?; + + //extend session auth + let _session_task = get_session_after_creation::(&private_key).await?; + let recipient = get_address_from_recipient::(to).await?; + let mut record_nonces: Vec = vec![]; + + let program_manager = + ProgramManager::::new(Some(private_key), None, Some(api_client.clone()), None)?; + + let program_id = format!("{}.aleo", asset_id); + + //get required records if private fee + let (fee_record, _fee_commitment, fee_id) = match fee_private { + true => { + let (fee_record, _fee_commitment, fee_id) = + find_aleo_credits_record_to_spend::(fee, vec![])?; + + let fee_nonce = fee_record.nonce().to_string(); + record_nonces.push(fee_nonce); + + update_record_spent_local::(&fee_id, true)?; + (Some(fee_record), Some(_fee_commitment), Some(fee_id)) + } + false => (None, None, None), + }; + + let mut pending_transaction = TransactionPointer::::new( + Some(to.to_string()), + None, + TransactionState::Processing, + None, + Some(program_id.clone()), + Some("transfer_public_to_private".to_string()), + vec![], + record_nonces, + Local::now(), + None, + message, + EventTypeCommon::Send, + Some(*amount as f64 / 1000000.0), + Some(*fee as f64 / 1000000.0), + None, + ); + + let pending_tx_id = pending_transaction.encrypt_and_store(sender_address)?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_tx_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + } + }; + + // update spent states + if let Some(fee_id) = fee_id.clone() { + update_record_spent_local::(&fee_id, true)?; + } + + let transaction_id = match program_manager.transfer( + amount.to_owned(), + fee.to_owned(), + recipient, + TransferType::PublicToPrivate, + None, + None, + fee_record.clone(), + &program_id, + ) { + Ok(tx_id) => tx_id, + Err(e) => { + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, false)?; + } + + pending_transaction.update_failed_transaction( + "Transaction execution failed, no records were spent.".to_string(), + ); + + let encrypted_failed_transaction = + pending_transaction.to_encrypted_data(sender_address)?; + + update_encrypted_transaction_state_by_id( + &pending_tx_id, + &encrypted_failed_transaction.ciphertext, + &encrypted_failed_transaction.nonce, + TransactionState::Failed, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_tx_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + return Err(AvailError::new( + AvailErrorType::Internal, + "Error transferring tokens".to_string(), + format!("Error transferring tokens: {:?}", e), + )); + } + }; + + handle_encrypted_storage_and_message( + transaction_id, + recipient, + &pending_tx_id, + None, + fee_id, + false, + window, + ) + .await?; + + Ok(format!("Transaction Id {}", transaction_id.to_string())) +} + +/// Convert private tokens to public tokens +async fn transfer_private_to_public_util( + asset_id: &str, + amount: &u64, + fee: &u64, + fee_private: &bool, + message: Option, + to: &str, + password: Option, + window: Option, +) -> AvailResult { + let api_client = setup_client::()?; + let sender_address = get_address::()?; + let private_key = get_private_key::(password)?; + + //extend session auth + let _session_task = get_session_after_creation::(&private_key).await?; + let recipient = get_address_from_recipient::(to).await?; + let mut record_nonces: Vec = vec![]; + + let program_manager = + ProgramManager::::new(Some(private_key), None, Some(api_client.clone()), None).unwrap(); + + // get required records if private tx + let (token_record, _token_commitment, token_id) = + find_tokens_to_spend::(asset_id, amount, vec![])?; + let token_nonce = token_record.nonce().to_string(); + record_nonces.push(token_nonce); + + let (fee_record, _fee_commitment, fee_id) = match fee_private { + true => { + let (fee_record, _fee_commitment, fee_id) = + find_aleo_credits_record_to_spend::(fee, vec![])?; + + let fee_nonce = fee_record.nonce().to_string(); + record_nonces.push(fee_nonce); + + update_record_spent_local::(&fee_id, true)?; + (Some(fee_record), Some(_fee_commitment), Some(fee_id)) + } + false => (None, None, None), + }; + + let program_id = format!("{}.aleo", asset_id); + + let mut pending_transaction = TransactionPointer::::new( + Some(to.to_string()), + None, + TransactionState::Processing, + None, + Some(program_id.clone()), + Some("transfer_private_to_public".to_string()), + vec![], + record_nonces, + Local::now(), + None, + message, + EventTypeCommon::Send, + Some(*amount as f64 / 1000000.0), + Some(*fee as f64 / 1000000.0), + None, + ); + + let pending_tx_id = pending_transaction.encrypt_and_store(sender_address)?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_tx_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + // update spent states + update_record_spent_local::(&token_id, true)?; + if let Some(fee_id) = fee_id.clone() { + update_record_spent_local::(&fee_id, true)?; + } + + let transfer_res = match program_manager.transfer( + amount.to_owned(), + fee.to_owned(), + recipient, + TransferType::PrivateToPublic, + None, + Some(token_record.clone()), + fee_record.clone(), + &program_id, + ) { + Ok(tx_id) => tx_id, + Err(e) => { + update_record_spent_local::(&token_id, false)?; + + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, false)?; + } + + pending_transaction.update_failed_transaction( + "Transaction execution failed, no records were spent.".to_string(), + ); + + let encrypted_failed_transaction = + pending_transaction.to_encrypted_data(sender_address)?; + + update_encrypted_transaction_state_by_id( + &pending_tx_id, + &encrypted_failed_transaction.ciphertext, + &encrypted_failed_transaction.nonce, + TransactionState::Failed, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_tx_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + return Err(AvailError::new( + AvailErrorType::Internal, + "Error transferring tokens".to_string(), + format!("Error transferring tokens: {:?}", e), + )); + } + }; + + handle_encrypted_storage_and_message( + transfer_res, + recipient, + &pending_tx_id, + Some(token_id), + fee_id, + false, + window, + ) + .await?; + + Ok(format!("Transaction Id {}", transfer_res)) +} + +// Transfer tokens publicly +async fn transfer_public( + asset_id: &str, + amount: &u64, + fee: &u64, + fee_private: &bool, + message: Option, + to: &str, + password: Option, + window: Option, +) -> AvailResult { + let api_client = setup_client::()?; + let sender_address = get_address::()?; + let private_key = get_private_key::(password)?; + + //extend session auth + get_session_after_creation::(&private_key).await?; + let recipient = get_address_from_recipient::(to).await?; + + let program_manager = + ProgramManager::::new(Some(private_key), None, Some(api_client.clone()), None)?; + + let mut record_nonces: Vec = vec![]; + + // get required records if private fee + let (fee_record, _fee_commitment, fee_id) = match fee_private { + true => { + let (fee_record, _fee_commitment, fee_id) = + find_aleo_credits_record_to_spend::(fee, vec![])?; + + let fee_nonce = fee_record.nonce().to_string(); + record_nonces.push(fee_nonce); + + update_record_spent_local::(&fee_id, true)?; + (Some(fee_record), Some(_fee_commitment), Some(fee_id)) + } + false => (None, None, None), + }; + + let program_id = format!("{}.aleo", asset_id); + + let mut pending_transaction = TransactionPointer::::new( + Some(to.to_string()), + None, + TransactionState::Processing, + None, + Some(program_id.clone()), + Some("transfer_public".to_string()), + vec![], + record_nonces, + Local::now(), + None, + message, + EventTypeCommon::Send, + Some(*amount as f64 / 1000000.0), + Some(*fee as f64 / 1000000.0), + None, + ); + + let pending_tx_id = pending_transaction.encrypt_and_store(sender_address)?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_tx_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + // update spent states + if let Some(fee_id) = fee_id.clone() { + update_record_spent_local::(&fee_id, true)?; + } + + let transfer_res = match program_manager.transfer( + amount.to_owned(), + fee.to_owned(), + recipient, + TransferType::Public, + None, + None, + fee_record.clone(), + &program_id, + ) { + Ok(tx_id) => tx_id, + Err(e) => { + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, false)?; + } + + pending_transaction.update_failed_transaction( + "Transaction execution failed, no records were spent.".to_string(), + ); + + let encrypted_failed_transaction = + pending_transaction.to_encrypted_data(sender_address)?; + + update_encrypted_transaction_state_by_id( + &pending_tx_id, + &encrypted_failed_transaction.ciphertext, + &encrypted_failed_transaction.nonce, + TransactionState::Failed, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_tx_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + return Err(AvailError::new( + AvailErrorType::Internal, + "Error transferring tokens".to_string(), + format!("Error transferring tokens: {:?}", e), + )); + } + }; + + handle_encrypted_storage_and_message( + transfer_res, + recipient, + &pending_tx_id, + None, + fee_id, + false, + window, + ) + .await?; + + Ok(format!("Transaction Id {}", transfer_res)) +} + +// TODO - Add timer threshold for when to stop searching for transaction, and keep in unconfirmed state +/// Find Transaction on chain and handle state +pub fn find_confirmed_block_height( + tx_id: N::TransactionID, +) -> AvailResult<( + u32, + Vec>, + DateTime, + TransactionState, + Option, + Option>, + Option, +)> { + let api_client = setup_client::()?; + + let latest_block_height = api_client.latest_height()?; + + let mut flag: bool = false; + let mut iter = latest_block_height; + + let start_time = Instant::now(); + let search_duration = Duration::from_secs(180); + + println!("Waiting for transaction to confirm in block on chain"); + while !flag && start_time.elapsed() < search_duration { + println!("Checking block {}", iter); + let latest_height = api_client.latest_height()?; + + if iter > latest_height { + println!("Iter > Latest Height"); + std::thread::sleep(std::time::Duration::from_secs(3)); + continue; + } + + let block = match api_client.get_block(iter) { + Ok(block) => { + println!("Block {} found", iter); + block + } + Err(e) => { + println!("Error getting block: {:?}\n", e); + std::thread::sleep(std::time::Duration::from_secs(3)); + continue; + } + }; + + let transactions = block.transactions(); + + // transactions that where in excess of the max limit of the block + let aborted_transactions = block.aborted_transaction_ids(); + + if aborted_transactions.contains(&tx_id) { + flag = true; + let timestamp = get_timestamp_from_i64(block.timestamp())?; + return Ok(( + iter, + vec![], + timestamp, + TransactionState::Aborted, + None, + None, + None, + )); + } + + let tx = transactions.get(&tx_id); + + // TODO - Make it default to unconfirmed after 1 minute 30 seconds + println!("In Progress"); + if let Some(tx) = tx { + println!("Transaction found"); + // deduce state + + if let ConfirmedTransaction::::AcceptedDeploy(_, _, _) = tx { + flag = true; + let timestamp = get_timestamp_from_i64(block.timestamp())?; + let fee = tx.transaction().fee_amount()?; + let mut transitions: Vec> = vec![]; + + if let Some(fee_transition) = tx.transaction().fee_transition() { + let transition = fee_transition.transition(); + transitions.push(transition.clone()); + } + + return Ok(( + iter, + transitions, + timestamp, + TransactionState::Aborted, + None, + None, + Some(*fee as f64 / 1000000.0), + )); + } else if let ConfirmedTransaction::::AcceptedExecute(_, _, _) = tx { + flag = true; + println!("C1"); + let timestamp = get_timestamp_from_i64(block.timestamp())?; + println!("C2"); + let fee = tx.transaction().fee_amount()?; + println!("C3"); + + let transitions = tx.transitions().cloned().collect::>(); + println!("C4"); + return Ok(( + iter, + transitions, + timestamp, + TransactionState::Confirmed, + None, + None, + Some(*fee as f64 / 1000000.0), + )); + } + } else { + for tx in transactions.iter() { + if let ConfirmedTransaction::::RejectedDeploy(_, fee_tx, _, _) = tx { + if tx.to_unconfirmed_transaction_id()? == tx_id { + flag = true; + let timestamp = get_timestamp_from_i64(block.timestamp())?; + let fee = tx.transaction().fee_amount()?; + + let mut transitions: Vec> = vec![]; + + if let Some(fee_transition) = tx.transaction().fee_transition() { + let transition = fee_transition.transition(); + transitions.push(transition.clone()); + } + + return Ok(( + iter, + transitions, + timestamp, + TransactionState::Rejected, + Some(fee_tx.id()), + None, + Some(*fee as f64 / 1000000.0), + )); + } + } else if let ConfirmedTransaction::::RejectedExecute( + _, + fee_tx, + rejected_execution, + _, + ) = tx + { + if tx.to_unconfirmed_transaction_id()? == tx_id { + flag = true; + let timestamp = get_timestamp_from_i64(block.timestamp())?; + let fee = tx.transaction().fee_amount()?; + let transitions = tx.transitions().cloned().collect::>(); + if let Some(rejected_execution) = rejected_execution.execution() { + return Ok(( + iter, + transitions, + timestamp, + TransactionState::Rejected, + Some(fee_tx.id()), + Some(rejected_execution.to_owned()), + Some(*fee as f64 / 1000000.0), + )); + } + + return Ok(( + iter, + transitions, + timestamp, + TransactionState::Rejected, + Some(fee_tx.id()), + None, + Some(*fee as f64 / 1000000.0), + )); + } + } + } + } + + iter = iter.add(1); + std::thread::sleep(std::time::Duration::from_secs(7)); + } + + Err(AvailError::new( + AvailErrorType::NotFound, + "Transaction is unconfirmed, this might be due to issues with the Aleo network." + .to_string(), + "Transaction is unconfirmed, this might be due to issues with the Aleo network." + .to_string(), + )) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pre_install_inclusion_prover() -> AvailResult<()> { + let path = match dirs::home_dir() { + Some(home_dir) => home_dir + .join(".aleo") + .join("resources") + .join("inclusion.prover.cd85cc5"), + + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error getting home directory".to_string(), + "Error getting home directory".to_string(), + )) + } + }; + + if path.as_path().exists() { + println!("inclusion.prover.cd85cc5 already exists"); + Ok(()) + } else { + let client = reqwest::Client::new(); + + println!("Downloading inclusion.prover.cd85cc5..."); + + let task = tokio::spawn(async move { + client + .get("https://s3-us-west-1.amazonaws.com/aleo-resources/inclusion.prover.cd85cc5") + .send() + .await + }); + + let res = match task.await? { + Ok(res) => res, + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error downloading inclusion.prover.cd85cc5".to_string(), + format!("Error downloading inclusion.prover.cd85cc5: {:?}", e), + )) + } + }; + + println!("Finished downloading inclusion.prover.cd85cc5..."); + + let body = res.bytes().await?; + + fs::write(path, body)?; + + println!("Finished writing inclusion.prover.cd85cc5..."); + + Ok(()) + } +} + +#[cfg(test)] +mod transfer_tests { + + use crate::models::{ + storage::languages::Languages, + wallet_connect::{get_event::GetEventsRequest, records::GetRecordsRequest}, + }; + + use crate::services::account::generation::import_wallet; + use crate::services::account::key_management::key_controller::KeyController; + use crate::services::local_storage::session::view::VIEWSESSION; + use crate::services::local_storage::{ + encrypted_data::drop_encrypted_data_table, + persistent_storage::{delete_user_preferences, update_address}, + storage_api::{event::get_avail_events_raw, records::get_record_pointers}, + }; + use crate::services::record_handling::sync::txs_sync; + use avail_common::models::constants::*; + + use snarkvm::prelude::{Identifier, Testnet3}; + + #[cfg(target_os = "linux")] + use crate::services::account::key_management::key_controller::linuxKeyController; + + #[cfg(target_os = "macos")] + use crate::services::account::key_management::key_controller::macKeyController; + + #[cfg(target_os = "windows")] + use crate::services::account::key_management::key_controller::windowsKeyController; + + use super::*; + async fn test_setup_prerequisites() { + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let ext = Identifier::::from_str("test").unwrap(); + + #[cfg(target_os = "macos")] + let mac_key_controller = macKeyController {}; + #[cfg(target_os = "macos")] + mac_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + #[cfg(target_os = "linux")] + let linux_key_controller = linuxKeyController {}; + #[cfg(target_os = "linux")] + linux_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + #[cfg(target_os = "windows")] + let windows_key_controller = windowsKeyController {}; + #[cfg(target_os = "windows")] + windows_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + drop_encrypted_data_table().unwrap(); + delete_user_preferences().unwrap(); + // initialize the user preferences + + import_wallet( + Some("Satoshi".to_string()), + STRONG_PASSWORD.to_string(), + false, + &pk.to_string(), + false, + Languages::English, + ) + .await + .unwrap(); + } + + #[tokio::test] + async fn test_private_transfer() { + //NOTE - Don't forget to change OS depending on what you testing on -default should be linux + + /* -- Has to be called here cause has to await-- */ + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let ext = Identifier::::from_str("test").unwrap(); + + #[cfg(target_os = "macos")] + let mac_key_controller = macKeyController {}; + #[cfg(target_os = "macos")] + mac_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + #[cfg(target_os = "linux")] + let linux_key_controller = linuxKeyController {}; + #[cfg(target_os = "linux")] + linux_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + #[cfg(target_os = "windows")] + let windows_key_controller = windowsKeyController {}; + #[cfg(target_os = "windows")] + windows_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + drop_encrypted_data_table().unwrap(); + delete_user_preferences().unwrap(); + // initialize the user preferences + + import_wallet( + Some("Satoshi".to_string()), + STRONG_PASSWORD.to_string(), + false, + &pk.to_string(), + false, + Languages::English, + ) + .await + .unwrap(); + + let fee = 300000u64; + let amount = 900000u64; + let recipient_address = Address::::from_str(TESTNET_ADDRESS).unwrap(); + let asset_id = "credits".to_string(); + + let request = TransferRequest::new( + recipient_address.to_string(), + amount, + Some("Private Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::Private, + false, + fee, + asset_id, + ); + + transfer_raw::(request, None).await.unwrap(); + + /* --SETUP COMPLETE */ + + let get_records_request = GetRecordsRequest::new(None, None, None); + let (records, ids) = get_record_pointers::(get_records_request.clone()).unwrap(); + + println!("Initial Records: {:?}\n", records); + + let get_events_request = GetEventsRequest { + filter: None, + page: None, + }; + let events = get_avail_events_raw::(get_events_request.clone()).unwrap(); + + println!("Initial Events: {:?}\n", events); + + // call fee estimation + let fee = 300000u64; + let amount = 900000u64; + let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); + let asset_id = "credits".to_string(); + + let request = TransferRequest::new( + recipient_address.to_string(), + amount, + Some("Private Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::Private, + false, + fee, + asset_id, + ); + + transfer_raw::(request, None).await.unwrap(); + + // get events and display + let (records, _ids) = get_record_pointers::(get_records_request.clone()).unwrap(); + + println!("Post Private Transfer Sender Records: {:?}\n", records); + + let events = get_avail_events_raw::(get_events_request.clone()).unwrap(); + + println!("Post Private Transfer Sender Events: {:?}\n", events); + + let recipient_view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY).unwrap(); + let vk_bytes = recipient_view_key.to_bytes_le().unwrap(); + + VIEWSESSION + .set_view_session(&recipient_view_key.to_string()) + .unwrap(); + + update_address(&recipient_address.to_string()).unwrap(); + + let _res = txs_sync().await.unwrap(); + + let (records, ids) = get_record_pointers::(get_records_request).unwrap(); + + println!("Post Private Transfer Receiver Records: {:?}\n", records); + + let events = get_avail_events_raw::(get_events_request).unwrap(); + + println!("Post Private Transfer Receiver Events: {:?}\n", events); + } + + #[tokio::test] + async fn test_transfer_public_to_private() { + //NOTE - Don't forget to change OS depending on what you testing on -default should be linux + + /* -- Has to be called here cause has to await-- */ + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let ext = Identifier::::from_str("test").unwrap(); + + #[cfg(target_os = "macos")] + let mac_key_controller = macKeyController {}; + #[cfg(target_os = "macos")] + mac_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + #[cfg(target_os = "linux")] + let linux_key_controller = linuxKeyController {}; + #[cfg(target_os = "linux")] + linux_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + #[cfg(target_os = "windows")] + let windows_key_controller = windowsKeyController {}; + #[cfg(target_os = "windows")] + windows_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + drop_encrypted_data_table().unwrap(); + delete_user_preferences().unwrap(); + // initialize the user preferences + + import_wallet( + Some("Satoshi".to_string()), + STRONG_PASSWORD.to_string(), + false, + &pk.to_string(), + false, + Languages::English, + ) + .await + .unwrap(); + + let fee = 300000u64; + let amount = 900000u64; + let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); + let asset_id = "credits".to_string(); + + let request = TransferRequest::new( + recipient_address.to_string(), + amount, + Some("Public to Private Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::PublicToPrivate, + false, + fee, + asset_id, + ); + + transfer_raw::(request, None).await.unwrap(); + } + + #[tokio::test] + async fn test_transfer_private_to_public() { + //NOTE - Don't forget to change OS depending on what you testing on -default should be linux + + /* -- Has to be called here cause has to await-- */ + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let ext = Identifier::::from_str("test").unwrap(); + + #[cfg(target_os = "macos")] + let mac_key_controller = macKeyController {}; + #[cfg(target_os = "macos")] + mac_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + #[cfg(target_os = "linux")] + let linux_key_controller = linuxKeyController {}; + #[cfg(target_os = "linux")] + linux_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + #[cfg(target_os = "windows")] + let windows_key_controller = windowsKeyController {}; + #[cfg(target_os = "windows")] + windows_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + drop_encrypted_data_table().unwrap(); + delete_user_preferences().unwrap(); + // initialize the user preferences + + import_wallet( + Some("Satoshi".to_string()), + STRONG_PASSWORD.to_string(), + false, + &pk.to_string(), + false, + Languages::English, + ) + .await + .unwrap(); + + let fee = 300000u64; + let amount = 900000u64; + let recipient_address = Address::::from_str(TESTNET_ADDRESS).unwrap(); + let asset_id = "credits".to_string(); + + let request = TransferRequest::new( + recipient_address.to_string(), + amount, + Some("Public to Private Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::PublicToPrivate, + false, + fee, + asset_id, + ); + + transfer_raw::(request, None).await.unwrap(); + + /* --SETUP COMPLETE */ + + let fee = 4000000u64; + let amount = 100000u64; + let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); + let asset_id = "credits".to_string(); + + let request = TransferRequest::new( + recipient_address.to_string(), + amount, + Some("Private to Public Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::PrivateToPublic, + false, + fee, + asset_id, + ); + + transfer_raw::(request, None).await.unwrap(); + } + + #[tokio::test] + async fn test_transfer_public() { + //NOTE - Don't forget to change OS depending on what you testing on -default should be linux + + /* -- Has to be called here cause has to await-- */ + + let pk = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); + let ext = Identifier::::from_str("test").unwrap(); + + #[cfg(target_os = "macos")] + let mac_key_controller = macKeyController {}; + #[cfg(target_os = "macos")] + mac_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + #[cfg(target_os = "linux")] + let linux_key_controller = linuxKeyController {}; + #[cfg(target_os = "linux")] + linux_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + #[cfg(target_os = "windows")] + let windows_key_controller = windowsKeyController {}; + #[cfg(target_os = "windows")] + windows_key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + drop_encrypted_data_table().unwrap(); + delete_user_preferences().unwrap(); + // initialize the user preferences + + import_wallet( + Some("Satoshi".to_string()), + STRONG_PASSWORD.to_string(), + false, + &pk.to_string(), + false, + Languages::English, + ) + .await + .unwrap(); + /* --SETUP COMPLETE */ + + let fee = 4000000u64; + let amount = 100000u64; + let recipient_address = Address::::from_str("").unwrap(); + let asset_id = "credits".to_string(); + + let request = TransferRequest::new( + recipient_address.to_string(), + amount, + Some("Public Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::Public, + false, + fee, + asset_id, + ); + + transfer_raw::(request, None).await.unwrap(); + } + + // Transfer funds to test wallet on local dev network + #[tokio::test] + async fn test_transfer_public_to_private_util() { + let api_client = setup_client::().unwrap(); + let private_key = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + + let program_manager = ProgramManager::::new( + Some(private_key), + None, + Some(api_client.clone()), + None, + ) + .unwrap(); + + let program_id = format!("credits.aleo"); + + let recipient = Address::::from_str( + "aleo1wswguyd4gh045y9y2t36ks0wpk4yg3cpeded8cc8fjwud8j7dvystyl9lp", + ) + .unwrap(); + + let transaction_id = program_manager + .transfer( + 7000000, + 0, + recipient, + TransferType::PublicToPrivate, + None, + None, + None, + &program_id, + ) + .unwrap(); + } + + #[tokio::test] + async fn test_inclusion_prover() { + let _res = pre_install_inclusion_prover().await; + } +} diff --git a/src-tauri/src/services/record_handling/utils.rs b/src-tauri/src/services/record_handling/utils.rs new file mode 100644 index 00000000..0a114293 --- /dev/null +++ b/src-tauri/src/services/record_handling/utils.rs @@ -0,0 +1,2092 @@ +use avail_common::models::encrypted_data::EncryptedDataTypeCommon; +use chrono::{DateTime, Local}; +use snarkvm::circuit::Aleo; +use snarkvm::console::network::Testnet3; +use snarkvm::ledger::transactions::ConfirmedTransaction; +use snarkvm::prelude::{ + Address, Ciphertext, Entry, Execution, Field, GraphKey, Identifier, Itertools, Literal, + Network, Output, Plaintext, ProgramID, Record, RecordType, Transaction, Transition, Value, + ViewKey, +}; +use snarkvm::synthesizer::program::{Command, Instruction, ProgramCore}; +use snarkvm::utilities::ToBits; +use std::collections::HashMap; +use std::ops::Sub; +use std::str::FromStr; +use tauri::{Manager, Window}; + +use crate::api::{ + aleo_client::{setup_client, setup_local_client}, + encrypted_data::{post_encrypted_data, send_transaction_in}, + fee::{create_record, fetch_record}, + user::name_to_address, +}; + +use crate::helpers::validation::validate_address_bool; +use crate::models::event::EventTransition; +use crate::models::pointers::{ + deployment::DeploymentPointer, + message::TransactionMessage, + record::AvailRecord, + transaction::{ExecutedTransition, TransactionPointer}, +}; +use crate::models::wallet_connect::balance::Balance; + +use crate::models::wallet_connect::records::{GetRecordsRequest, RecordFilterType, RecordsFilter}; +use crate::services::local_storage::encrypted_data::get_encrypted_data_by_flavour; +use crate::services::local_storage::tokens::{ + add_balance, get_balance, get_program_id_for_token, if_token_exists, init_token, +}; +use crate::services::local_storage::{ + encrypted_data::{ + store_encrypted_data, update_encrypted_data_by_id, update_encrypted_data_synced_on_by_id, + update_encrypted_transaction_confirmed_by_id, update_encrypted_transaction_state_by_id, + }, + persistent_storage::{ + get_address, get_address_string, get_backup_flag, get_network, get_username, + }, + session::view::VIEWSESSION, + storage_api::{ + deployment::get_deployment_pointer, + records::{ + check_if_record_exists, encrypt_and_store_records, get_record_pointers, + update_record_spent_local, update_records_spent_backup, + }, + transaction::get_transaction_pointer, + }, +}; +use crate::services::record_handling::transfer::find_confirmed_block_height; + +use avail_common::{ + aleo_tools::program_manager::{Credits, ProgramManager}, + errors::{AvailError, AvailErrorType, AvailResult}, + models::encrypted_data::{EncryptedData, EventTypeCommon, RecordTypeCommon, TransactionState}, + models::{fee_request::FeeRequest, network::SupportedNetworks}, +}; + +use super::decrypt_transition::DecryptTransition; + +/// Gets all tags from a given block height to the latest block height +pub fn get_tags(min_block_height: u32) -> AvailResult> { + let api_client = setup_client::()?; + let latest_height = api_client.latest_height()?; + + let step = 49; + + let mut end_height = latest_height; + let mut start_height = latest_height.sub(step); + + let mut tags: Vec = vec![]; + for _ in (min_block_height..latest_height).step_by(step as usize) { + println!("start_height: {:?}", start_height); + println!("end_height: {:?}", end_height); + let blocks = api_client.get_blocks(start_height, end_height)?; + + let field_tags: Vec<_> = blocks.iter().flat_map(|block| block.tags()).collect(); + let _ = field_tags.iter().map(|tag| tags.push(tag.to_string())); + + end_height = start_height; + start_height = start_height.saturating_sub(step); + } + + Ok(tags) +} + +/// This is to check if a record is spent or not +/// TODO: Needs to be made much faster to be included in txs_sync -> Deprecate +/// Note this is only used in txs_sync just in case the user has spent the records he is receiving already from a different wallet. +fn spent_checker( + block_height: u32, + local_tags: Vec, +) -> AvailResult<(Vec, Vec)> { + let api_client = setup_client::()?; + let latest_height = api_client.latest_height()?; + + let step = 49; + + let mut end_height = latest_height; + let mut start_height = latest_height.sub(step); + + let spent_tags: Vec = vec![]; + for _ in (block_height..latest_height).step_by(step as usize) { + println!("start_height: {:?}", start_height); + println!("end_height: {:?}", end_height); + let blocks = api_client.get_blocks(start_height, end_height)?; + + let tags: Vec<_> = blocks.iter().flat_map(|block| block.tags()).collect(); + + let tags = tags + .iter() + .map(|tag| tag.to_string()) + .collect::>(); + + //check if tags contains any of the local tags and make a vector of bools representing if the local tags are spent or not + let mut result = vec![]; + for local_tag in local_tags.clone() { + if tags.contains(&local_tag) { + result.push(local_tag); + } + } + + // Search in reverse order from the latest block to the earliest block + end_height = start_height; + start_height = start_height.saturating_sub(step); + } + + //check what local tags are not in result and add them as unspent + let mut unspent_tags: Vec = vec![]; + for local_tag in local_tags { + if !spent_tags.contains(&local_tag) { + unspent_tags.push(local_tag); + } + } + + Ok((spent_tags, unspent_tags)) +} + +pub fn transition_to_record( + transition: &Transition, + commitment: &str, + index: u8, +) -> AvailResult<( + Record>, + Record>, + HashMap, +)> { + let v_key = VIEWSESSION.get_instance::()?; + let output = transition.outputs(); + + let record = match output.get(index as usize) { + Some(output) => output.clone().into_record(), + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Record not found".to_string(), + "Record not found".to_string(), + )) + } + }; + + if let Some((r_commitment, record)) = record { + if r_commitment.to_string() == commitment { + let decrypted_record = record.decrypt(&v_key)?; + let data_map = decrypted_record + .data() + .iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect::>(); + Ok((decrypted_record, record, data_map)) + } else { + Err(AvailError::new( + AvailErrorType::Internal, + "Record not found".to_string(), + "Record not found".to_string(), + )) + } + } else { + Err(AvailError::new( + AvailErrorType::Internal, + "Record not found".to_string(), + "Record not found".to_string(), + )) + } +} + +/// Updates spent state of records if the tag matches the transition input tag +pub fn input_spent_check( + transition: &Transition, + spent: bool, +) -> AvailResult> { + let inputs = transition.inputs(); + + let mut spent_ids: Vec = vec![]; + + let filter = RecordsFilter::new( + vec![transition.program_id().to_string()], + None, + RecordFilterType::Unspent, + None, + ); + let get_records_request = GetRecordsRequest::new(None, Some(filter), None); + let (record_pointers, ids) = get_record_pointers::(get_records_request)?; + + for input in inputs { + let input_tag = match input.tag() { + Some(tag) => tag, + None => continue, + }; + + for (record_pointer, id) in record_pointers.iter().zip(ids.iter()) { + if &record_pointer.tag()? == input_tag { + update_record_spent_local::(id, spent)?; + spent_ids.push(id.to_string()); + } + } + } + + Ok(spent_ids) +} + +/// Gets record name from program using the index of the output record +pub fn get_record_name( + program: ProgramCore, Command>, + function_id: &Identifier, + output_index: usize, +) -> AvailResult { + let function = program.get_function(function_id).unwrap(); + + let output = function.outputs()[output_index].clone(); + + Ok(output.value_type().to_string()) +} + +pub fn get_record_type( + program: ProgramCore, Command>, + record_name: String, + record: Record>, +) -> AvailResult { + let mut token_count = 0; + let mut nft_count = 0; + + let functions = program.functions().clone().into_keys(); + for function in functions { + let fn_str = function.to_string(); + match fn_str.as_str() { + _ if fn_str.contains("approve_public") => token_count = token_count + 1, + _ if fn_str.contains("unapprove_public") => token_count = token_count + 1, + _ if fn_str.contains("transfer_from_public") => token_count = token_count + 1, + _ if fn_str.contains("transfer_public") => token_count = token_count + 1, + _ if fn_str.contains("transfer") => token_count = token_count + 1, + _ if fn_str.contains("transfer_private") => token_count = token_count + 1, + _ if fn_str.contains("transfer_private_to_public") => token_count = token_count + 1, + _ if fn_str.contains("transfer_public_to_private") => token_count = token_count + 1, + _ if fn_str.contains("mint") => token_count = token_count + 1, + _ if fn_str.contains("mint_private") => token_count = token_count + 1, + _ if fn_str.contains("split") => token_count = token_count + 1, + _ if fn_str.contains("join") => token_count = token_count + 1, + _ if fn_str.contains("deposit") => token_count = token_count + 1, + _ if fn_str.contains("withdraw") => token_count = token_count + 1, + _ if fn_str.contains("burn") => token_count = token_count + 1, + _ if fn_str.contains("create") => token_count = token_count + 1, + _ if fn_str.contains("init") => token_count = token_count + 1, + + // -------- NFT -------- + _ if fn_str.contains("initialize") => nft_count = nft_count + 1, + _ if fn_str.contains("initialize_collection") => nft_count = nft_count + 1, + _ if fn_str.contains("add_nft") => nft_count = nft_count + 1, + _ if fn_str.contains("admin") => nft_count = nft_count + 1, + _ if fn_str.contains("register") => nft_count = nft_count + 1, + _ if fn_str.contains("minting") => nft_count = nft_count + 1, + _ if fn_str.contains("add_minter") => nft_count = nft_count + 1, + _ if fn_str.contains("update_toggle_settings") => nft_count = nft_count + 1, + _ if fn_str.contains("set_mint_block") => nft_count = nft_count + 1, + _ if fn_str.contains("transfer") => nft_count = nft_count + 1, + _ if fn_str.contains("update_symbol") => nft_count = nft_count + 1, + _ if fn_str.contains("update_base_uri") => nft_count = nft_count + 1, + _ if fn_str.contains("open_mint") => nft_count = nft_count + 1, + _ if fn_str.contains("mint") => nft_count = nft_count + 1, + _ if fn_str.contains("claim_nft") => nft_count = nft_count + 1, + _ if fn_str.contains("claim") => nft_count = nft_count + 1, + _ if fn_str.contains("burn_nft") => nft_count = nft_count + 1, + _ if fn_str.contains("burn") => nft_count = nft_count + 1, + _ => {} + } + } + let mut nft_record_flag = 0; + let mut token_record_flag = 0; + for key in record.data().clone().into_keys() { + match key.to_string().as_str() { + "data" => nft_record_flag = nft_record_flag + 1, + "edition" => nft_record_flag = nft_record_flag + 1, + "amount" => token_record_flag = token_record_flag + 1, + _ => {} + } + } + if (token_count >= 7 && token_record_flag >= 1) { + return Ok(RecordTypeCommon::Tokens); + } else if (nft_count >= 8 && nft_record_flag >= 2) { + return Ok(RecordTypeCommon::NFT); + } else { + return Ok(RecordTypeCommon::None); + } +} + +/// Derives all record pointers from a transition and returns them as a vector +pub fn transition_to_record_pointer( + transaction_id: N::TransactionID, + transition: Transition, + block_height: u32, + view_key: ViewKey, +) -> AvailResult>> { + let address = view_key.to_address(); + let address_x_coordinate = address.to_x_coordinate(); + let sk_tag = GraphKey::try_from(view_key)?.sk_tag(); + let api_client = setup_client::()?; + + let outputs = transition.outputs(); + let mut records: Vec> = vec![]; + + for (index, output) in outputs.iter().enumerate() { + let record = output.clone().into_record(); + + let rp = match record { + Some((commitment, record)) => { + match record.is_owner_with_address_x_coordinate(&view_key, &address_x_coordinate) { + true => { + let record = match record.decrypt(&view_key) { + Ok(record) => record, + Err(_) => { + return Err(AvailError::new( + AvailErrorType::SnarkVm, + "Error decrypting record".to_string(), + "Error decrypting record".to_string(), + )) + } + }; + + match check_if_record_exists::(&record.nonce().to_string())? { + true => continue, + false => {} + } + + let program_id = transition.program_id(); + let mut record_type = RecordTypeCommon::None; + let program = api_client.get_program(program_id)?; + let record_name = + get_record_name(program.clone(), transition.function_name(), index)?; + // check if its in the records table + if if_token_exists(&record_name.clone())? { + if record_name == "credits.record" { + record_type = RecordTypeCommon::AleoCredits; + } else { + record_type = RecordTypeCommon::Tokens; + } + + let balance = get_record_type_and_amount::( + record.clone(), + record_name.clone(), + view_key, + )?; + add_balance::( + record_name.clone().as_str(), + balance.to_string().as_str(), + view_key, + )?; + } else { + record_type = match program_id.to_string().as_str() { + "credits.aleo" => RecordTypeCommon::AleoCredits, + _ => get_record_type( + program.clone(), + record_name.clone(), + record.clone(), + )?, + }; + if record_type == RecordTypeCommon::Tokens + || record_type == RecordTypeCommon::AleoCredits + { + let balance = get_record_type_and_amount::( + record.clone(), + record_name.clone(), + view_key, + )?; + init_token::( + record_name.clone().as_str(), + &program_id.to_string(), + view_key.to_address().to_string().as_str(), + balance.to_string().as_str(), + )?; + } + } + + let record_pointer = AvailRecord::from_record( + commitment, + &record, + sk_tag, + record_type, + &program_id.to_string(), + block_height, + transaction_id, + transition.id().to_owned(), + &transition.function_name().to_string(), + record_name, + index as u8, + &record.owner().to_string(), + )?; + + let encrypted_record_pointer = record_pointer.to_encrypted_data(address)?; + + store_encrypted_data(encrypted_record_pointer)?; + Some(record_pointer) + } + false => None, + } + } + None => None, + }; + + if let Some(rp) = rp { + records.push(rp); + } + } + + Ok(records) +} + +pub fn get_record_type_and_amount( + record: Record>, + record_name: String, + view_key: ViewKey, +) -> AvailResult { + if record.data().clone().is_empty() { + Ok("".to_string()) + } else { + let mut balance = "".to_string(); + for key in record.data().clone().into_keys() { + let is_key: bool = match key.to_string().as_str() { + "amount" => true, + "microcredits" => true, + _ => false, + }; + if is_key { + let balance_entry = match record.data().get(&key.clone()) { + Some(bal) => Ok(bal), + None => Err(()), + }; + let balance_f = match balance_entry.unwrap() { + Entry::Private(Plaintext::Literal(Literal::::U64(amount), _)) => { + let balance_field = amount.to_be_bytes(); + balance = format!("{}u64", u64::from_be_bytes(balance_field).to_string()); + } + Entry::Private(Plaintext::Literal(Literal::::U128(amount), _)) => { + let balance_field = amount.to_be_bytes(); + let bal_t = u128::from_be_bytes(balance_field); + balance = format!("{}u64", u64::try_from(bal_t)?.to_string()); + } + _ => todo!(), + }; + // let balance_field = balance_f.to_be_bytes(); + // balance = format!("{}u64", u64::from_be_bytes(balance_field).to_string()); + } + } + Ok(balance) + } +} + +pub fn output_to_record_pointer( + transaction_id: N::TransactionID, + transition_id: N::TransitionID, + function_id: &Identifier, + program_id: &ProgramID, + output: &Output, + block_height: u32, + view_key: ViewKey, + index: usize, +) -> AvailResult<(Option>, Option)> { + let address_x_coordinate = view_key.to_address().to_x_coordinate(); + let sk_tag = GraphKey::try_from(view_key)?.sk_tag(); + + let record = output.clone().into_record(); + + match record { + Some((commitment, record)) => { + match record.is_owner_with_address_x_coordinate(&view_key, &address_x_coordinate) { + true => { + let record = match record.decrypt(&view_key) { + Ok(record) => record, + Err(_) => return Ok((None, None)), + }; + + match check_if_record_exists::(&record.nonce().to_string())? { + true => return Ok((None, None)), + false => {} + } + + let api_client = setup_client::()?; + let program = api_client.get_program(program_id)?; + let record_name = get_record_name(program.clone(), function_id, index)?; + let mut balance = "".to_string(); + + let mut record_type = RecordTypeCommon::None; + if if_token_exists(&record_name.clone())? { + if record_name.clone() == "credits.record" { + record_type = RecordTypeCommon::AleoCredits; + } else { + record_type = RecordTypeCommon::Tokens; + } + + balance = get_record_type_and_amount::( + record.clone(), + record_name.clone(), + view_key, + )?; + add_balance::( + record_name.clone().as_str(), + balance.to_string().as_str(), + view_key, + )?; + } else { + record_type = match program_id.to_string().as_str() { + "credits.aleo" => RecordTypeCommon::AleoCredits, + _ => get_record_type( + program.clone(), + record_name.clone(), + record.clone(), + )?, + }; + + if record_type == RecordTypeCommon::Tokens + || record_type == RecordTypeCommon::AleoCredits + { + balance = get_record_type_and_amount::( + record.clone(), + record_name.clone(), + view_key, + )?; + init_token::( + record_name.clone().as_str(), + &program_id.to_string(), + view_key.to_address().to_string().as_str(), + balance.to_string().as_str(), + )?; + } + } + let record_pointer = AvailRecord::from_record( + commitment, + &record.clone(), + sk_tag, + record_type, + &program_id.to_string(), + block_height, + transaction_id, + transition_id, + &function_id.to_string(), + record_name.clone(), + index as u8, + &record.owner().to_string(), + )?; + + Ok((Some(record_pointer), Some(balance))) + } + false => Ok((None, None)), + } + } + None => Ok((None, None)), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_all_nft_data() -> AvailResult> { + let network = get_network()?; + + match SupportedNetworks::from_str(network.as_str())? { + SupportedNetworks::Testnet3 => { + let nft_data = get_all_nft_raw::()?; + Ok(nft_data) + } + _ => Err(AvailError::new( + AvailErrorType::Internal, + "Network not supported".to_string(), + "Network not supported".to_string(), + )), + } +} + +pub fn get_all_nft_raw() -> AvailResult> { + let nft_encrypted_data = + get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record).unwrap(); + let v_key = VIEWSESSION.get_instance::().unwrap(); + + let records = nft_encrypted_data + .iter() + .map(|x| { + let encrypted_data = x.to_enrypted_struct::().unwrap(); + let block: AvailRecord = encrypted_data.decrypt(v_key).unwrap(); + block + }) + .collect::>>(); + + let plaintexts: Vec>> = records + .iter() + .filter(|&record| record.metadata.record_type == RecordTypeCommon::NFT) // NFT Records + .filter_map(|record: &AvailRecord| match record.to_record() { + Ok(record) => Some(record), + Err(e) => None, + }) + .collect::>(); + + fn u128_to_string(u: u128) -> String { + let mut temp_u128 = u; + let mut bytes = vec![] as Vec; + + while temp_u128 > 0u128 { + let byte = (temp_u128 & 0xff) as u8; + bytes.push(byte); + temp_u128 >>= 8; + } + + bytes.reverse(); + + String::from_utf8(bytes).unwrap() + } + + let full_urls = plaintexts + .iter() + .filter_map(|record| { + let data1 = record + .data() + .clone() + .get(&Identifier::::from_str("data1").unwrap()) + .cloned()?; + + let data2 = record + .data() + .clone() + .get(&Identifier::::from_str("data2").unwrap()) + .cloned()?; + + match (data1, data2) { + ( + Entry::Private(Plaintext::Literal(Literal::::U128(data1), _)), + Entry::Private(Plaintext::Literal(Literal::::U128(data2), _)), + ) => { + let data1 = u128_to_string(*data1); + let data2 = u128_to_string(*data2); + Some(format!("{}{}", data1, data2)) + } + _ => None, + } + }) + .collect::>(); + + Ok(full_urls) +} + +/// Helper to parse the mapping value from the program mapping +fn parse_with_suffix(input: &str) -> Result { + //remove last three characters + let input = &input[..input.len() - 3]; + input.parse::() +} + +/// Get public balance for any ARC20 token +pub fn get_public_token_balance(asset_id: &str) -> AvailResult { + let address = get_address_string()?; + let record_name = format!("{}.record", asset_id); + // let program_id = format!("{}.aleo", asset_id); + let mut program_id = get_program_id_for_token(&record_name)?; + if (program_id == "") { + program_id = format!("{}.aleo", asset_id); + } + println!("===> PROGRAM ID FOR FETCH {:?}", program_id); + let api_client = setup_client::()?; + + let credits_mapping = match api_client.get_mapping_value(program_id, "account", &address) { + Ok(credits_mapping) => credits_mapping, + Err(e) => match e.to_string().as_str() { + "Mapping not found" => return Ok(0.0), + _ => return Err(e.into()), + }, + }; + + let pub_balance = parse_with_suffix(&credits_mapping.to_string())? as f64; + + println!("pub_balance: {:?}", pub_balance); + + Ok(pub_balance / 1000000.0) +} + +/// Get private balance for any ARC20 token +pub fn get_private_token_balance(asset_id: &str) -> AvailResult { + let address = get_address_string()?; + let record_name = format!("{}.record", asset_id); + let program_id = format!("{}.aleo", asset_id); + println!("===> Asset ID in get_private_balance() {:?}", asset_id); + + let vk = VIEWSESSION.get_instance::()?; + let balance = get_balance(&record_name, vk)?; + + println!("balance: {:?}", balance); + let balance_trimmed = balance.trim_end_matches("u64"); + + Ok(balance_trimmed.parse::()? as f64 / 1000000.0) +} + +/// Get Arc20 Token Balance +pub fn get_token_balance(asset_id: &str) -> AvailResult { + let asset_id_modified = asset_id.to_string(); + let asset_id_final = asset_id.to_string().replace(".record", ""); + println!("===> Asset ID after mpod {:?}", asset_id_final); + let public = get_public_token_balance::(&asset_id_final)?; + let private = get_private_token_balance::(&asset_id_final)?; + println!("===> Token Balance of {:?}", asset_id_final); + println!("public: {:?}", public); + println!("private: {:?}", private); + + Ok(Balance::new(public, private)) +} + +/// Handles encrypted message passing and updated transaction state +pub async fn handle_encrypted_storage_and_message( + transaction_id: N::TransactionID, + recipient_address: Address, + transaction_pointer_id: &str, + input_id: Option, + fee_id: Option, + wallet_connect: bool, + window: Option, +) -> AvailResult<()> { + let username = get_username()?; + let backup = get_backup_flag()?; + let view_key = VIEWSESSION.get_instance::()?; + + let sender_address = get_address::()?; + + let mut processing_transaction_pointer = get_transaction_pointer::(transaction_pointer_id)?; + processing_transaction_pointer.update_pending_transaction(); + + let encrypted_pending_transaction = + processing_transaction_pointer.to_encrypted_data(sender_address)?; + + update_encrypted_transaction_state_by_id( + transaction_pointer_id, + &encrypted_pending_transaction.ciphertext, + &encrypted_pending_transaction.nonce, + TransactionState::Pending, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &transaction_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + // search for the transaction on chain + let ( + block_height, + transitions, + timestamp, + transaction_state, + fee_tx_id, + rejected_execution, + fee, + ) = find_confirmed_block_height::(transaction_id)?; + + println!("State of transaction: {:?}", transaction_state); + + if transaction_state == TransactionState::Rejected { + // input record was not spent in this case + if let Some(input_id) = input_id { + update_record_spent_local::(&input_id, false)?; + } + + //TODO - Do not double subtract input id + handle_transaction_rejection( + processing_transaction_pointer, + transaction_pointer_id, + rejected_execution, + fee_tx_id, + block_height, + fee, + sender_address, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &transaction_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + // Check for remainder of private fee given back as new record + for transition in transitions { + transition_to_record_pointer(transaction_id, transition, block_height, view_key)?; + } + + return Ok(()); + } else if transaction_state == TransactionState::Aborted { + // records were not spent in this case + if let Some(input_id) = input_id { + update_record_spent_local::(&input_id, false)?; + } + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, false)?; + } + + processing_transaction_pointer.update_aborted_transaction( + "Transaction aborted by the Aleo blockchain. No tokens were spent.".to_string(), + transaction_id, + block_height, + ); + + let updated_encrypted_transaction = + processing_transaction_pointer.to_encrypted_data(sender_address)?; + + update_encrypted_transaction_state_by_id( + transaction_pointer_id, + &updated_encrypted_transaction.ciphertext, + &updated_encrypted_transaction.nonce, + TransactionState::Aborted, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &transaction_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + return Ok(()); + } + + let mut execution_transitions: Vec> = vec![]; + let mut spent_ids: Vec = vec![]; + + let records = transitions + .iter() + .filter(|transition| !transition.is_fee_public()) + .map(|transition| { + let transition = transition.to_owned(); + + if !transition.is_fee_private() { + if wallet_connect { + let mut transition_spent_ids = match input_spent_check::(&transition, true) { + Ok(transition_spent_ids) => transition_spent_ids, + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Error checking input spent".to_string(), + )) + } + }; + + spent_ids.append(&mut transition_spent_ids); + } + + let executed_transition = ExecutedTransition::::new( + transition.program_id().to_string(), + transition.function_name().to_string(), + transition.id().to_owned(), + ); + + execution_transitions.push(executed_transition); + } + + let record_pointers = + transition_to_record_pointer(transaction_id, transition, block_height, view_key)?; + + println!("record_pointers found from transfer: {:?}", record_pointers); + + Ok(record_pointers) + }) + .collect::>>>>()? + .concat(); + + handle_transaction_confirmed::( + transaction_pointer_id, + transaction_id, + execution_transitions, + block_height, + timestamp, + fee, + sender_address, + )?; + + println!("Inshallah confirmed"); + let mut confirmed_transaction_pointer = get_transaction_pointer::(transaction_pointer_id)?; + println!("{:?}", confirmed_transaction_pointer); + + //check if private fee was spent + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, true)?; + if backup { + spent_ids.push(fee_id); + } + } + + //update token input was spent + if let Some(input_id) = input_id { + update_record_spent_local::(&input_id, true)?; + if backup { + spent_ids.push(input_id); + } + } + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &transaction_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + if sender_address != recipient_address { + let transaction_message = TransactionMessage::::new( + transaction_id, + block_height, + username, + processing_transaction_pointer.message(), + ); + + let encrypted_transaction_message = + transaction_message.to_encrypted_data(recipient_address)?; + + send_transaction_in(encrypted_transaction_message).await?; + } + + Ok(()) +} + +/// Handles updating pending transaction and encrypted storage +pub async fn handle_transaction_update_and_encrypted_storage( + transaction_id: N::TransactionID, + transaction_pointer_id: &str, + fee_id: Option, + window: Option, +) -> AvailResult<()> { + let backup = get_backup_flag()?; + let view_key = VIEWSESSION.get_instance::()?; + + let sender_address = get_address::()?; + + // Update transaction to pending to confirm + let mut processing_transaction_pointer = get_transaction_pointer::(transaction_pointer_id)?; + processing_transaction_pointer.update_pending_transaction(); + + let encrypted_pending_transaction = + processing_transaction_pointer.to_encrypted_data(sender_address)?; + + update_encrypted_transaction_state_by_id( + transaction_pointer_id, + &encrypted_pending_transaction.ciphertext, + &encrypted_pending_transaction.nonce, + TransactionState::Pending, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &transaction_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + let ( + block_height, + transitions, + timestamp, + transaction_state, + fee_tx_id, + rejected_execution, + fee, + ) = find_confirmed_block_height::(transaction_id)?; + + if transaction_state == TransactionState::Rejected { + // Check for remainder of private fee given back as new record + for transition in transitions { + transition_to_record_pointer(transaction_id, transition, block_height, view_key)?; + } + + handle_transaction_rejection( + processing_transaction_pointer, + transaction_pointer_id, + rejected_execution, + fee_tx_id, + block_height, + fee, + sender_address, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &transaction_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + return Ok(()); + } else if transaction_state == TransactionState::Aborted { + // fee was not consumed in this case + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, false)?; + } + + //TODO - Update record spent state for input nonces + + processing_transaction_pointer.update_aborted_transaction( + "Transaction aborted by the Aleo blockchain. No tokens were spent.".to_string(), + transaction_id, + block_height, + ); + let updated_encrypted_transaction = + processing_transaction_pointer.to_encrypted_data(sender_address)?; + update_encrypted_transaction_state_by_id( + transaction_pointer_id, + &updated_encrypted_transaction.ciphertext, + &updated_encrypted_transaction.nonce, + TransactionState::Aborted, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &transaction_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + return Ok(()); + } + + let mut execution_transitions: Vec> = vec![]; + let mut spent_ids: Vec = vec![]; + + let records = transitions + .iter() + .filter(|transition| !transition.is_fee_public()) + .map(|transition| { + let transition = transition.to_owned(); + + if !transition.is_fee_private() { + let mut transition_spent_ids = input_spent_check::(&transition, true)?; + spent_ids.append(&mut transition_spent_ids); + + let executed_transition = ExecutedTransition::::new( + transition.program_id().to_string(), + transition.function_name().to_string(), + transition.id().to_owned(), + ); + + execution_transitions.push(executed_transition); + } + + let record_pointer = + transition_to_record_pointer(transaction_id, transition, block_height, view_key)?; + Ok(record_pointer) + }) + .collect::>>>>()? + .concat(); + + handle_transaction_confirmed::( + transaction_pointer_id, + transaction_id, + execution_transitions, + block_height, + timestamp, + fee, + sender_address, + )?; + + //TODO - Do not double subtract fee + //check if private fee was spent + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, true)?; + if backup { + spent_ids.push(fee_id); + } + } + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &transaction_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + Ok(()) +} + +// TODO - Handle fee remainder for deployment handler +/// Handles updating deployment transaction and encrypted storage +pub async fn handle_deployment_update_and_encrypted_storage( + transaction_id: N::TransactionID, + deployment_pointer_id: &str, + fee_id: Option, + window: Option, +) -> AvailResult<()> { + let backup = get_backup_flag()?; + let sender_address = get_address::()?; + let view_key = VIEWSESSION.get_instance::()?; + + // Update transaction to pending to confirm + let mut processing_deployment_pointer = get_deployment_pointer::(deployment_pointer_id)?; + processing_deployment_pointer.update_pending_deployment(); + + let encrypted_pending_deployment = + processing_deployment_pointer.to_encrypted_data(sender_address)?; + + update_encrypted_transaction_state_by_id( + deployment_pointer_id, + &encrypted_pending_deployment.ciphertext, + &encrypted_pending_deployment.nonce, + TransactionState::Pending, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &deployment_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + let (block_height, transitions, _, transaction_state, _fee_tx_id, _, fee) = + find_confirmed_block_height::(transaction_id)?; + + if transaction_state == TransactionState::Rejected { + for transition in transitions { + input_spent_check(&transition, true)?; + transition_to_record_pointer( + transaction_id, + transition.clone(), + block_height, + view_key, + )?; + } + + handle_deployment_rejection( + processing_deployment_pointer, + deployment_pointer_id, + transaction_id, + block_height, + fee, + sender_address, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &deployment_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + return Ok(()); + } else if transaction_state == TransactionState::Aborted { + // fee was not consumed in this case + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, false)?; + } + + processing_deployment_pointer.update_aborted_deployment( + "Transaction aborted by the Aleo blockchain. No tokens were spent.".to_string(), + transaction_id, + block_height, + ); + let updated_encrypted_deployment = + processing_deployment_pointer.to_encrypted_data(sender_address)?; + update_encrypted_transaction_state_by_id( + deployment_pointer_id, + &updated_encrypted_deployment.ciphertext, + &updated_encrypted_deployment.nonce, + TransactionState::Aborted, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &deployment_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + return Ok(()); + } + + //checking for remainder if private fee was spent + for transition in transitions { + input_spent_check(&transition, true)?; + transition_to_record_pointer(transaction_id, transition.clone(), block_height, view_key)?; + } + + handle_deployment_confirmed( + deployment_pointer_id, + transaction_id, + block_height, + fee, + sender_address, + )?; + + // if record was spent on fee update state + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, true)?; + + if backup { + update_records_spent_backup::(vec![fee_id]).await?; + } + } + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &deployment_pointer_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + }; + + Ok(()) +} + +pub fn handle_deployment_confirmed( + pointer_id: &str, + tx_id: N::TransactionID, + block_height: u32, + fee: Option, + sender_address: Address, +) -> AvailResult<()> { + let mut pending_transaction_pointer = get_deployment_pointer::(pointer_id)?; + + pending_transaction_pointer.update_confirmed_deployment(tx_id, block_height, fee); + let updated_encrypted_transaction = + pending_transaction_pointer.to_encrypted_data(sender_address)?; + + update_encrypted_data_by_id( + pointer_id, + &updated_encrypted_transaction.ciphertext, + &updated_encrypted_transaction.nonce, + )?; + + Ok(()) +} + +pub fn handle_deployment_rejection( + mut pointer: DeploymentPointer, + pointer_id: &str, + tx_id: N::TransactionID, + block_height: u32, + fee: Option, + sender_address: Address, +) -> AvailResult<()> { + pointer.update_rejected_deployment( + "Transaction rejected by the Aleo blockchain.".to_string(), + Some(tx_id), + block_height, + fee, + ); + + let updated_encrypted_deployment = pointer.to_encrypted_data(sender_address)?; + + update_encrypted_transaction_state_by_id( + pointer_id, + &updated_encrypted_deployment.ciphertext, + &updated_encrypted_deployment.nonce, + TransactionState::Rejected, + )?; + + Ok(()) +} + +pub fn handle_transaction_rejection( + mut pointer: TransactionPointer, + pointer_id: &str, + rejected_execution: Option>, + tx_id: Option, + block_height: u32, + fee: Option, + sender_address: Address, +) -> AvailResult<()> { + // NOTE - If bugs out change to update via input nonces + if let Some(rejected_execution) = rejected_execution { + let rejected_transitions = rejected_execution.transitions(); + + for transition in rejected_transitions { + if !transition.is_fee_private() { + input_spent_check::(transition, false)?; + } + } + } + + pointer.update_rejected_transaction( + "Transaction rejected by the Aleo blockchain.".to_string(), + tx_id, + block_height, + fee, + ); + + let updated_encrypted_transaction = pointer.to_encrypted_data(sender_address)?; + + update_encrypted_transaction_state_by_id( + pointer_id, + &updated_encrypted_transaction.ciphertext, + &updated_encrypted_transaction.nonce, + TransactionState::Rejected, + )?; + + Ok(()) +} + +pub fn handle_transaction_confirmed( + transaction_pointer_id: &str, + tx_id: N::TransactionID, + execution_transitions: Vec>, + block_height: u32, + timestamp: DateTime, + fee: Option, + sender_address: Address, +) -> AvailResult<()> { + let mut pending_transaction_pointer = get_transaction_pointer::(transaction_pointer_id)?; + + pending_transaction_pointer.update_confirmed_transaction( + tx_id, + block_height, + execution_transitions, + timestamp, + TransactionState::Confirmed, + fee, + ); + + let updated_encrypted_transaction = + pending_transaction_pointer.to_encrypted_data(sender_address)?; + + let program_ids = match updated_encrypted_transaction.clone().program_ids { + Some(program_ids) => program_ids, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Program ids not found".to_string(), + "Program ids not found".to_string(), + )) + } + }; + + let function_ids = match updated_encrypted_transaction.clone().function_ids { + Some(function_ids) => function_ids, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Function ids not found".to_string(), + "Function ids not found".to_string(), + )) + } + }; + + update_encrypted_transaction_confirmed_by_id( + transaction_pointer_id, + &updated_encrypted_transaction.ciphertext, + &updated_encrypted_transaction.nonce, + &program_ids, + &function_ids, + )?; + + Ok(()) +} + +/// Sync transaction whilst scanning blocks +pub fn sync_transaction( + transaction: &ConfirmedTransaction, + block_height: u32, + timestamp: DateTime, + message: Option, + from: Option, +) -> AvailResult<( + Option, + Vec>, + Vec, + bool, +)> { + let view_key = VIEWSESSION.get_instance::()?; + let address = view_key.to_address(); + + let mut record_pointers: Vec> = vec![]; + let mut encrypted_transition_pointers: Vec = vec![]; + + let mut execution_transitions: Vec> = vec![]; + let mut found_flag = false; + + let state = check_transaction_state::(transaction)?; + + for transition in transaction.transitions() { + let ownership_check = match DecryptTransition::owns_transition( + view_key, + *transition.tpk(), + *transition.tcm(), + ) { + Ok(res) => res, + Err(_e) => false, + }; + + if ownership_check { + input_spent_check(&transition.clone(), true)?; + + let execution_transition = ExecutedTransition::::new( + transition.program_id().to_string(), + transition.function_name().to_string(), + transition.id().to_owned(), + ); + + if !transition.is_fee_private() && !transition.is_fee_public() { + execution_transitions.push(execution_transition); + } + + let mut transition_record_pointers = transition_to_record_pointer::( + transaction.id().to_owned(), + transition.clone(), + block_height, + view_key, + )?; + + record_pointers.append(&mut transition_record_pointers); + } else { + let (mut transition_record_pointers, mut encrypted_transitions, _transition_spent_ids) = + DecryptTransition::check_inputs_outputs_inclusion::( + view_key, + transition.clone(), + transaction.id().to_owned(), + timestamp, + block_height, + message.clone(), + from.clone(), + )?; + + record_pointers.append(&mut transition_record_pointers); + if !transition.is_fee_private() && !transition.is_fee_public() { + encrypted_transition_pointers.append(&mut encrypted_transitions); + } + + found_flag = true; + } + } + + let execution_transaction = match !execution_transitions.is_empty() { + true => { + let inner_tx = transaction.transaction(); + let fee = match inner_tx.fee_amount() { + Ok(fee) => *fee as f64 / 1000000.0, + Err(_) => { + return Err(AvailError::new( + AvailErrorType::SnarkVm, + "Error calculating fee".to_string(), + "Issue calculating fee".to_string(), + )) + } + }; + + println!("Fee found from external execution: {:?}", fee); + + let execution_tx = TransactionPointer::::new( + None, + Some(transaction.id().to_owned()), + state, + Some(block_height), + None, + None, + execution_transitions, + vec![], + timestamp, + Some(timestamp), + None, + EventTypeCommon::Execute, + None, + Some(fee), + None, + ); + + let encrypted_exec_tx = execution_tx.to_encrypted_data(address)?; + store_encrypted_data(encrypted_exec_tx.clone())?; + + found_flag = true; + + Some(encrypted_exec_tx) + } + false => None, + }; + + Ok(( + execution_transaction, + record_pointers, + encrypted_transition_pointers, + found_flag, + )) +} + +pub fn check_transaction_state( + transaction: &ConfirmedTransaction, +) -> AvailResult { + if let ConfirmedTransaction::::AcceptedExecute(_, _, _) = transaction { + Ok(TransactionState::Confirmed) + } else if let ConfirmedTransaction::::AcceptedDeploy(_, _, _) = transaction { + Ok(TransactionState::Confirmed) + } else if let ConfirmedTransaction::::RejectedExecute(_, _, _, _) = transaction { + //TODO - Return rejected execution + + Ok(TransactionState::Rejected) + } else if let ConfirmedTransaction::::RejectedDeploy(_, _, _, _) = transaction { + Ok(TransactionState::Rejected) + } else { + Ok(TransactionState::Pending) + } +} + +pub fn get_executed_transitions( + transaction: &Transaction, + block_height: u32, +) -> AvailResult>> { + let view_key = VIEWSESSION.get_instance::()?; + let mut execution_transitions: Vec> = vec![]; + + for transition in transaction.transitions() { + input_spent_check(transition, true)?; + + let ownership_check = match DecryptTransition::owns_transition( + view_key, + *transition.tpk(), + *transition.tcm(), + ) { + Ok(res) => res, + Err(_e) => false, + }; + + if ownership_check { + let execution_transition = ExecutedTransition::::new( + transition.program_id().to_string(), + transition.function_name().to_string(), + transition.id().to_owned(), + ); + + if !transition.is_fee_private() && !transition.is_fee_public() { + execution_transitions.push(execution_transition); + } + + transition_to_record_pointer( + transaction.id(), + transition.clone(), + block_height, + view_key, + )?; + } + } + + Ok(execution_transitions) +} + +pub fn get_fee_transition( + transaction_id: N::TransactionID, +) -> AvailResult { + let view_key = VIEWSESSION.get_instance::()?; + let api_client = setup_client::()?; + + let transaction = match api_client.get_transaction(transaction_id) { + Ok(transaction) => transaction, + Err(_) => { + return Err(AvailError::new( + AvailErrorType::Node, + "Transaction not found".to_string(), + "Transaction not found".to_string(), + )) + } + }; + let fee_transition = transaction.fee_transition(); + + match fee_transition { + Some(fee_transition) => { + let transition = fee_transition.transition(); + let (inputs, outputs) = + DecryptTransition::decrypt_inputs_outputs(view_key, transition)?; + let fee_event_transition = EventTransition::new( + transition.id().to_string(), + transition.program_id().to_string(), + transition.function_name().to_string(), + inputs, + outputs, + ); + Ok(fee_event_transition) + } + None => Err(AvailError::new( + AvailErrorType::Internal, + "Fee transition not found".to_string(), + "Fee transition not found".to_string(), + )), + } +} + +pub async fn get_address_from_recipient(recipient: &str) -> AvailResult> { + match validate_address_bool(recipient) { + true => { + let address = Address::::from_str(recipient)?; + Ok(address) + } + false => name_to_address(recipient).await, + } +} + +/* --Wallet Connect Utilities-- */ + +pub fn to_commitment( + record: Record>, + program_id: &ProgramID, + record_name: &Identifier, +) -> AvailResult> { + //construct the input as `(program_id || record_name || record)`. + let mut input = program_id.to_bits_le(); + record_name.write_bits_le(&mut input); + record.write_bits_le(&mut input); + + //Compute the BHP hash of the program record input. + let commitment = match N::hash_bhp1024(&input) { + Ok(commitment) => commitment, + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + e.to_string(), + "Record input commitment not found".to_string(), + )) + } + }; + + Ok(commitment) +} + +pub fn parse_inputs( + inputs: Vec, + function_identifier: &str, +) -> AvailResult<(Vec>, Vec, Option>, Option)> { + // check if input is address + let mut values: Vec> = vec![]; + let mut nonces: Vec = vec![]; + let mut recipient_address: Option> = None; + let mut amount = None; + + for (_index, input) in inputs.iter().enumerate() { + // Check if value is address + if validate_address_bool(input) { + recipient_address = Some(Address::::from_str(input)?); + let value = Value::from_str(input)?; + values.push(value); + } else { + //check if value is record + match Record::>::from_str(input) { + Ok(record) => { + let nonce = record.nonce().to_string(); + nonces.push(nonce); + let value = Value::Record(record); + values.push(value); + } + Err(_) => { + let value = Value::from_str(input)?; + values.push(value); + + // value is constant plaintext input + if function_identifier.contains("transfer") { + let trimmed_input = input.trim_end_matches("u64"); + + if let Ok(amount_found) = trimmed_input.parse::() { + amount = Some(amount_found as f64 / 1000000.0); + } + } + } + } + } + } + + Ok((values, nonces, recipient_address, amount)) +} + +pub async fn estimate_fee( + program_id: &str, + function_id: &str, + inputs: Vec>, + program_manager: ProgramManager, +) -> AvailResult +where + N: Network, + A: Aleo, +{ + // Get the program from chain, error if it doesn't exist + let program = program_manager.api_client()?.get_program(program_id)?; + + let function_identifier = Identifier::::from_str(function_id)?; + // API Call to see if record already exists + let _fee_value = 0i32; + let _if_exists = true; + match fetch_record(program_id.to_string(), function_id.to_string()).await? { + // Return the fee amount if the record exists + Some(x) => Ok(u64::try_from(x)?), + // Estimate the fee and also initiate an API call to Fee Estimation Microservice to create a record for the program. + None => { + let (fee, (_storage_fee, _namespace_fee), execution) = program_manager + .estimate_execution_fee::(&program, function_identifier, inputs.iter())?; + let execution_vector = + FeeRequest::to_bytes_execution_object::(execution.clone()).await; + match execution_vector { + Ok(execution_vec) => { + let request = FeeRequest::new( + execution_vec, + program_id.to_string(), + function_id.to_string(), + SupportedNetworks::Testnet3, + ); + println!("Sending a request to Avail's Fee Estimation Microservice to add the fee data"); + let result: String = create_record(request).await?; + println!("{:?}", result); + } + Err(_e) => (), + } + println!("Execution Fee: {}", fee); + Ok(fee) + } + } +} + +// ======================================================== TESTS ======================================================== +#[cfg(test)] +mod test { + use std::{ + fmt::format, + ptr::null, + time::{Duration, Instant}, + }; + + use avail_common::{ + aleo_tools::{ + api::AleoAPIClient, + test_utils::{AVAIL_NFT_TEST, RECORD_NFT_CLAIM, RECORD_NFT_MINT, TOKEN_MINT}, + }, + models::constants::{ + TESTNET3_ADDRESS, TESTNET3_PRIVATE_KEY, TESTNET_ADDRESS, TESTNET_PRIVATE_KEY, + }, + }; + use snarkvm::{ + circuit::{environment::Private, AleoV0}, + prelude::{Parser, PrivateKey, Transaction}, + synthesizer::Program, + }; + use tokio::time::sleep; + + use crate::{models::pointers::record::Metadata, services::local_storage::tokens::get_balance}; + + use super::*; + use snarkvm::prelude::Testnet3; + #[tokio::test] + async fn test_get_all_nft_data() { + let res = get_all_nft_data().unwrap(); + println!("res\n {:?}", res); + } + // #[tokio::test] + // async fn test_token_record() { + // let mut api_client = setup_client::().unwrap(); + // let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + // let pk_3 = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); + // let vk = ViewKey::::try_from(pk).unwrap(); + // let vk_3 = ViewKey::::try_from(pk_3).unwrap(); + // let fee = 10000u64; + // let program_id = "token_avl_4.aleo"; + // // INPUTS + // let address_to_mint = Value::::try_from(TESTNET3_ADDRESS).unwrap(); + // let amt_input = Value::::try_from("100u64").unwrap(); + // let transfer_amt = Value::::try_from("1u64").unwrap(); + // let fee = 10000u64; + + // // let token_program = Program::::from_str(TOKEN_PROGRAM).unwrap(); + // let token_mint_program = Program::::from_str(TOKEN_MINT).unwrap(); + // let mut program_manager = + // ProgramManager::::new(Some(pk), None, Some(api_client.clone()), None) + // .unwrap(); + // let mut program_manager_3 = + // ProgramManager::::new(Some(pk_3), None, Some(api_client.clone()), None) + // .unwrap(); + // // program_manager.add_program(&token_program); + // program_manager.add_program(&token_mint_program); + // program_manager_3.add_program(&token_mint_program); + + // STEP - 0 DEPLOY PROGRAM (DONT NEED TO DEPLOY AGAIN) + // let deployement_id = program_manager.deploy_program("token_avl_4.aleo", 10000u64, None, None).unwrap(); + // println!("----> Program Deployed - {:?}", deployement_id); + // let mint_program: Result, Command>, snarkvm::prelude::Error> = api_client.get_program("token_avl.aleo"); + + // STEP - 1 MINT ****ONLY FOR TESTING PURPOSES**** + // let inputs = vec![address_to_mint.clone(), amt_input.clone()]; + // let mint_tokens = program_manager.execute_program(program_id, "mint_public", inputs.iter(), fee, None, None).unwrap().to_string(); + // println!("----> Tokens Minted - {:?}", mint_tokens); + + // let mint_txn = api_client.get_transaction(::TransactionID::from_str("at17hlupnq8nutyzvdccj5smhf6s8u7yzplwjf38xzqgl93486r3c8s9mrhuc").unwrap()).unwrap(); + // println!("----> Mint Tokens TXN - {:?}", mint_txn); + + // STEP - 2 QUERY MAPPING TO VERIFY + // let mapping_op = program_manager.get_mapping_value(program_id, "account", TESTNET3_ADDRESS).unwrap(); + // println!("----> Mapping Value - {:?}", mapping_op); + + // STEP - 4 PREPARE TOKEN RECORD BY USING transfer_public_to_private() fn + // let inputs = vec![address_to_mint.clone(), transfer_amt.clone()]; + // let token_record = program_manager_3.execute_program(program_id, "transfer_public_to_private", inputs.iter(),fee, None, None).unwrap().to_string(); + // let record_txn = api_client.get_transaction(::TransactionID::from_str(&token_record).unwrap()).unwrap(); + + // println!("----> Token Record TXN - {:?}", record_txn); + + // let record_txn_id = ::TransactionID::from_str("at18r5vumc27swqw0vtm9gp4la0cwg8nxk4njm49sp2dj7anp596c9qgaz66w").unwrap(); + // let record_txn = api_client.get_transaction(::TransactionID::from_str("at18r5vumc27swqw0vtm9gp4la0cwg8nxk4njm49sp2dj7anp596c9qgaz66w").unwrap()).unwrap(); + // // println!("----> Token Record TXN - {:?}", record_txn); + // let mut latest_height = api_client.latest_height().unwrap(); + // for transition in record_txn.clone().into_transitions(){ + // println!("INN"); + // if transition.program_id().to_string() == program_id { + // println!("OKK"); + // let record_pointer_token = transition_to_record_pointer::(record_txn.clone().id(), transition.clone(), latest_height, vk_3).unwrap(); + + // println!("----> Token Record - {:?}", record_pointer_token); + // } + // } + + // STEP - 4 QUERY LOCAL STORAGE TO VERIFY + // let mapping_op = program_manager + // .get_mapping_value(program_id, "account", TESTNET3_ADDRESS) + // .unwrap(); + // println!("----> Mapping Value - {:?}", mapping_op); + // let local_db_value = get_balance("token_avl_4.record", vk_3).unwrap(); + // println!("----> Local DB Value - {:?}", local_db_value); + // } + + // #[test] + // fn test_get_private_balance() { + // let _res = get_private_token_balance::("credits").unwrap(); + + // println!("res: {:?}", _res); + // } + + // #[test] + // fn get_public_balance() { + // get_public_token_balance::("credits").unwrap(); + // } + + // #[tokio::test] + // async fn test_estimate_fee() { + + // let program_id = "credits.aleo"; + // let function_id = "transfer_public"; + + // let inputs = vec![ + // // Value::::try_from(TESTNET_ADDRESS).unwrap(), + // Value::::try_from(TESTNET3_ADDRESS).unwrap(), + // Value::::try_from("10000u64").unwrap(), + // // Value::::try_from("true").unwrap() + // ]; + + // //let inputs = vec![]; + + // let api_client = setup_client::().unwrap(); + + // let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + // let program_manager = + // ProgramManager::::new(Some(pk), None, Some(api_client), None).unwrap(); + // let start = Instant::now(); + // let res = + // estimate_fee::(program_id, function_id, inputs, program_manager) + // .await.unwrap(); + // println!("ELAPSED TIME: {:?}",start.elapsed()); + // println!("res: {:?}", res); + // } + // } + + // #[tokio::test] + // async fn test_nft_record(){ + // // ARRANGE + // let mut api_client = setup_client::().unwrap(); + // // ALEO INPUTS + // let program_id = "avail_nft_0.aleo"; + // let nft_program = Program::::from_str(AVAIL_NFT_TEST).unwrap(); + // let total = Value::::try_from("10u128").unwrap(); + // let symbol = Value::::try_from("19212u128").unwrap(); + // let token_id = Value::::try_from("{ + // data1: 146324u128, + // data2: 823446u128 + // }").unwrap(); + // let base_uri = Value::::try_from("{ + // data0: 143324u128, + // data1: 883746u128, + // data2: 993843u128, + // data3: 932838u128 + // }").unwrap(); + // let edition = Value::::try_from("0scalar").unwrap(); + // let owner = Value::::try_from(TESTNET_ADDRESS).unwrap(); + // let amount = Value::::try_from("3u8").unwrap(); + // let settings = Value::::try_from("3u32").unwrap(); + // let block = Value::::try_from("64400u32").unwrap(); //UPDATE ASPER VALUE + // let hiding_nonce = Value::::try_from("1234scalar").unwrap(); + // // let record_NFT_mint = Value::::Record(Record::>::from_str(RECORD_NFT_MINT).unwrap()); + // // let record_NFT_claim = Value::::Record(Record::>::from_str(RECORD_NFT_CLAIM).unwrap()); + // // Program manager + // let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + // let vk = ViewKey::::try_from(pk).unwrap(); + // let fee = 10000u64; + // let mut program_manager = + // ProgramManager::::new(Some(pk), None, Some(api_client.clone()), None).unwrap(); + // program_manager.add_program(&nft_program); + // // ACT + // // ============================== DOCUMENTATION FOR TESTING ============================== + // // STEP - 0 DEPLOY PROGRAM (DONT NEED TO DEPLOY AGAIN) + // // let deployement_id = program_manager.deploy_program(program_id, 10000u64, None, None).unwrap(); + // // println!("----> Program Deployed - {:?}", deployement_id); + + // let program = program_manager.get_program(program_id).unwrap(); + + // // ALEO FUNCTIONS EXECUTION FLOW STARTS HERE + // // Comment out steps that you finish executing + // // STEP - 1 initialize_collection() + // // let init_inputs = vec![total.clone(), symbol.clone(), base_uri.clone()]; + // // let init_txn_id = program_manager.execute_program(program_id, "initialize_collection", init_inputs.iter(), 10000u64, None, None).unwrap().to_string(); + // // println!("----> Initialised a NFT Collection (TXN-ID) - {:?}", init_txn_id); + + // // // STEP - 2 add_nft() + // // let add_nft_inputs = vec![token_id.clone(), edition.clone()]; + // // let add_nft_txn_id = program_manager.execute_program(program_id, "add_nft", add_nft_inputs.iter(), fee, None, None).unwrap().to_string(); + // // println!("----> Added a NFT to the Collection (TXN-ID) - {:?}", add_nft_txn_id); + + // // // Get the txn_id from the output and get_transaction() using the output + // // // STEP - 3 add_minter() + // // let add_minter_inputs = vec![owner.clone(), amount.clone()]; + // // let add_minter_txn_id = program_manager.execute_program(program_id, "add_minter", add_minter_inputs.iter(), fee, None, None).unwrap().to_string(); + // // println!("----> Added a Minter to the Collection (TXN-ID) - {:?}", add_nft_txn_id); + // // sleep(Duration::from_secs(20)).await; + // // println!("Waited 20 secs for the TXN to Broadcast "); + // let add_minter_txn = api_client.get_transaction(::TransactionID::from_str("at1uete9wa8w993ndy6e0hsynvap0yfpzru82ps5tm3hx6g908p3upsf8kl8s").unwrap()).unwrap();//(::TransactionID::from_str(&add_minter_txn_id).unwrap()).unwrap(); + // println!("----> Minter TXN owner for checking - {:?}", add_minter_txn.owner()); + // // let record_pointer_NFT_mint = + // let mut nonce = "".to_string(); + // let mut commitment = "".to_string(); + // let mut latest_height = api_client.latest_height().unwrap(); + // for transition in add_minter_txn.clone().into_transitions(){ + // if transition.program_id().to_string() == program_id { + // let record_pointer_NFT_mint = transition_to_record_pointer(add_minter_txn.clone().id(), transition.clone(), latest_height, vk).unwrap(); + // // STEP - 4 set_mint_block() + // for record in record_pointer_NFT_mint{ + // let mint_block = format!("{}u32",record.pointer.block_height); + // let mint_block_inputs = vec![Value::::try_from(mint_block.to_string()).unwrap()]; + // // let block_txn_id = program_manager.execute_program(program_id, "set_mint_block", mint_block_inputs.iter(), fee, None, None).unwrap().to_string(); + // // println!("----> Updated block number (TXN-ID) - {:?}", block_txn_id); + + // nonce = record.metadata.nonce; + // commitment = record.pointer.commitment; + + // } + // } + // } + // // SETUP NFT_MINT RECORD + // let NFT_mint_record = format!("{}{}{}", RECORD_NFT_MINT, nonce, ".public }"); + // println!("----> NFT_mint.record created and stored - {:?}", NFT_mint_record); + // // STEP - 5 update_toggle_settings() + // let settings_inputs = vec![settings.clone()]; + // // let settings_txn_id = program_manager.execute_program(program_id, "update_toggle_settings", settings_inputs.iter(), fee, None, None).unwrap().to_string(); + // // println!("----> Updated settings to allow minting without whitelisting (TXN-ID) - {:?}", settings_txn_id); + + // // STEP - 6 open_mint() + // // let open_mint_inputs = vec![hiding_nonce.clone()]; + // // let open_mint_txn_id = program_manager.execute_program(program_id, "open_mint", open_mint_inputs.iter(), fee, None, None).unwrap().to_string(); + // // println!("----> Open Mint function invoked (TXN-ID) - {:?}", open_mint_txn_id); + // let open_mint_txn = api_client.get_transaction(::TransactionID::from_str("at1xj60pnlgzg0tc5ntm2n02vll93uq4xtretadjzea343h2qgl8gzq4m0yuk").unwrap()).unwrap(); + // let mut claim_nonce = "".to_string(); + // let mut claim = "0field"; + // let mut latest_height = api_client.latest_height().unwrap(); + // for transition in open_mint_txn.clone().into_transitions(){ + // if transition.program_id().to_string() == program_id { + // let record_pointer_NFT_claim = transition_to_record_pointer(add_minter_txn.clone().id(), transition.clone(), latest_height, vk).unwrap(); + // for record in record_pointer_NFT_claim{ + // claim_nonce = record.metadata.nonce; + // } + // let ops = &transition.outputs()[1]; + // println!("----> Claim value fetch sucessful - {:?}", ops); + // } + // } + // // SETUP NFT_CLAIM RECORD + // let NFT_claim_record = format!("{}{}{}", RECORD_NFT_CLAIM, claim_nonce, ".public }"); + // println!("----> NFT_claim.record created and stored - {:?}", NFT_claim_record); + + // // STEP - 7 mint() + // let mint_inputs = vec![Value::::Record(Record::>::from_str(&NFT_mint_record.clone()).unwrap()) ,hiding_nonce.clone()]; + // let mint_txn_id = program_manager.execute_program(program_id, "mint", mint_inputs.iter(), fee, None, None).unwrap().to_string(); + // println!("----> Mint function invoked (TXN-ID) - {:?}", mint_txn_id); + + // // STEP - 8 claim_nft() + // let nft_inputs = vec![Value::::Record(Record::>::from_str(&NFT_claim_record.clone()).unwrap()) ,token_id.clone(), edition.clone()]; + // let nft_txn_id = program_manager.execute_program(program_id, "claim_nft", nft_inputs.iter(), fee, None, None).unwrap().to_string(); + // println!("----> NFT Claimed (TXN-ID) - {:?}", nft_txn_id); + + // // // FINAL STEP - SEND THE TRANSITION TO FUNCTION TO GET RECORD TYPE + // let nft_txn = api_client.get_transaction(::TransactionID::from_str("at1ya42tgdqawkkwf5t8ezuez954j3lgpv92xqhlcc0eajfnzrwlc9qhgve9y").unwrap()).unwrap(); + // for transition in nft_txn.clone().into_transitions(){ + // if transition.program_id().to_string() == program_id { + // let record_pointer_NFT = transition_to_record_pointer(add_minter_txn.clone().id(), transition.clone(), latest_height, vk).unwrap(); + + // println!("----> NFT Fetched sucessfully - {:?}", record_pointer_NFT); + // } + // } + + // } + // // fn get_nonce(txn: Transaction, program_id: &str, api_client: AleoAPIClient, vk: ViewKey ) -> Metadata{ + // let latest_height = api_client.latest_height().unwrap(); + // for transition in txn.into_transitions(){ + // if transition.program_id().to_string() == program_id { + // println!("----> Transition Found - {:?}", transition.id()); + // let res = transition_to_record_pointer(txn.id(), transition.clone(), latest_height, vk).unwrap(); + // let metadata = for record in res.iter(){ + // return record.metadata; + // } + // } + // } + // return (); + // } +} diff --git a/src-tauri/src/services/records.rs b/src-tauri/src/services/records.rs new file mode 100644 index 00000000..b8f67a43 --- /dev/null +++ b/src-tauri/src/services/records.rs @@ -0,0 +1,127 @@ +// Multi Threaded get_records - in construction FIX: Output not matching +//gets the records form the latest aleo blocks and forms and returns a vector of our local block type +/* +fn get_nova_records(last_sync: u32) -> AvailResult<(Vec, Vec)> { + let view_key = get_view_session::()?; + + let api_client = AleoAPIClient::::local_testnet3("3030"); + let chunk_size = 49; + + let latest_height = api_client.latest_height()?; + + let total_blocks_num = latest_height.sub(last_sync); + let num_chunks = total_blocks_num / chunk_size; + + let chunk_ranges: Vec<(u32, u32)> = (0..num_chunks) + .map(|chunk_index| { + let start_block = chunk_index * chunk_size; + let end_block = (start_block + chunk_size).min(total_blocks_num); + (start_block, end_block) + }) + .collect(); + + let synced_encrypted_blocks = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Block)? + .iter() + .map(|data| Ok(deserialize(&data.data)?)) + .collect::, AvError>>()?; + + //decrypt and form a vector of block heights + let synced_blocks = synced_encrypted_blocks + .iter() + .map(|block| Block::decrypt(block.to_owned()).unwrap()) + .map(|block| block.block_height) + .collect::>(); + + let address_x_coordinate = view_key.to_address().to_x_coordinate(); + + let sk_tag = GraphKey::try_from(view_key)?.sk_tag(); + + let mut end_height = latest_height; + let mut start_height = latest_height.sub(step_size); + + let mut tags: Vec = vec![]; + let mut new_record_blocks: Vec = vec![]; + + for _ in (last_sync..latest_height).step_by(step_size as usize) { + println!("start_height: {:?}", start_height); + println!("end_height: {:?}", end_height); + let blocks = api_client.get_blocks(start_height, end_height)?; + + let blocks = match blocks { + Ok(res) => res, + Err(_) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error getting blocks".to_string(), + "".to_string(), + )); + } + }; + + tags.append(&mut current_tags); + + //remove any blocks that are already synced + let blocks = blocks + .clone() + .into_iter() + .filter(|block| !synced_blocks.contains(&block.height())) + .collect::>>(); + + let mut optimized_blocks = blocks + .iter() + .map(|block| { + let records = block.clone().into_records(); + let height = block.height(); + + let identifiers = records + .into_iter() + .filter(|(_, record)| { + record.is_owner_with_address_x_coordinate(&view_key, &address_x_coordinate) + }) + .filter_map(|(commitment, record)| { + let record = record.decrypt(&view_key).ok()?; + let tag = Record::>::tag(sk_tag, commitment).ok()?; + let amount = record.microcredits().ok()?; + if amount == 0 { + None + } else { + Some(Identifiers::new( + commitment.to_string(), + tag.to_string(), + amount, + "unspent".to_string(), + )) + } + }) + .collect(); + + Block::new(height, identifiers) + }) + .collect::>(); + + // Search in reverse order from the latest block to the earliest block + end_height = start_height; + start_height = start_height.saturating_sub(step_size); + if start_height < last_sync { + start_height = last_sync + }; + + Ok(avail_blocks) + }) + + + let tags = tags.into_inner(); + + let tags = match tags { + Ok(res) => res, + Err(_) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Mutex error ".to_string(), + "".to_string(), + )); + } + }; + + Ok((new_record_blocks, tags)) +}*/ diff --git a/src-tauri/src/services/wallet_connect_api.rs b/src-tauri/src/services/wallet_connect_api.rs new file mode 100644 index 00000000..030f18f9 --- /dev/null +++ b/src-tauri/src/services/wallet_connect_api.rs @@ -0,0 +1,1011 @@ +use super::{ + local_storage::{ + encrypted_data::update_encrypted_transaction_state_by_id, + persistent_storage::{get_address, get_address_string, get_network}, + session::{password::PASS, view::VIEWSESSION}, + storage_api::{ + event::{ + get_avail_event_raw, get_avail_events_raw, get_event_raw, get_events_raw, + get_succinct_avail_event_raw, get_succinct_avail_events_raw, + }, + records::{ + get_page_count_for_filter, get_record_pointers, update_record_spent_local, + update_record_spent_local_via_nonce, + }, + }, + utils::{get_private_key, sign_message}, + }, + record_handling::{ + records::find_aleo_credits_record_to_spend, + utils::{ + get_token_balance, handle_deployment_update_and_encrypted_storage, + handle_encrypted_storage_and_message, handle_transaction_update_and_encrypted_storage, + parse_inputs, + }, + }, +}; +use chrono::Local; +use std::str::FromStr; + +use crate::api::aleo_client::setup_client; +use crate::models::event::{AvailEvent, SuccinctAvailEvent}; +use crate::models::pointers::{deployment::DeploymentPointer, transaction::TransactionPointer}; +use crate::models::wallet_connect::{ + balance::{BalanceRequest, BalanceResponse}, + create_event::{CreateEventRequest, CreateEventResponse}, + decrypt::{DecryptRequest, DecryptResponse}, + get_event::{GetEventRequest, GetEventResponse, GetEventsRequest, GetEventsResponse}, + records::{GetRecordsRequest, GetRecordsResponse, RecordWithPlaintext}, + sign::{SignatureRequest, SignatureResponse}, +}; + +use snarkvm::circuit::Aleo; +use snarkvm::{ + circuit::{AleoV0, Environment}, + prelude::{Address, Ciphertext, Field, Network, Program, Record, Signature, Testnet3}, +}; + +use tauri::{Manager, Window}; + +use avail_common::{ + aleo_tools::program_manager::*, + converters::messages::{field_to_fields, utf8_string_to_bits}, + errors::{AvailError, AvailErrorType, AvailResult}, + models::{ + encrypted_data::{EventTypeCommon, TransactionState}, + network::SupportedNetworks, + }, +}; + +#[tauri::command(rename_all = "snake_case")] +pub fn get_balance(request: BalanceRequest) -> AvailResult { + let network = get_network()?; + println!( + "===> Asset ID in Request Backend {:?}", + Some(request.asset_id()) + ); + //TODO - Read ARC20 to deduce assets id something like {program_id/record_name} seems reasonable. + let asset_id = match request.asset_id() { + Some(asset_id) => asset_id, + None => "credits".to_string(), + }; + println!("===> Asset ID in Backend {:?}", asset_id); + //TODO - V2 HD wallet support + let _address = match request.address() { + Some(address) => address.to_string(), + None => get_address_string()?, + }; + + let balance = match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => get_token_balance::(&asset_id)?, + _ => get_token_balance::(&asset_id)?, //SupportedNetworks::Mainnet => get_aleo_balance::()?, + }; + + Ok(BalanceResponse::new(vec![balance], None)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn request_create_event( + request: CreateEventRequest, + fee_private: bool, + window: Window, +) -> AvailResult { + let network = get_network()?; + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + request_create_event_raw::(request, fee_private, Some(window)).await + } + _ => request_create_event_raw::(request, fee_private, Some(window)).await, //SupportedNetworks::Mainnet => request_create_event_raw::(request), + } +} + +pub async fn request_create_event_raw>( + request: CreateEventRequest, + fee_private: bool, + window: Option, +) -> AvailResult { + let api_client = setup_client::()?; + let private_key = match get_private_key::(None) { + Ok(private_key) => { + PASS.extend_session()?; + private_key + } + Err(e) => match e.error_type { + AvailErrorType::Unauthorized => { + if let Some(window) = window { + match window.emit("reauthenticate", "create-event") { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting reauthentication event".to_string(), + "Error emitting reauthentication state".to_string(), + )); + } + }; + } + + return Ok(CreateEventResponse::new( + None, + Some("Unauthorized, please reauthenticate.".to_string()), + )); + } + _ => { + return Ok(CreateEventResponse::new( + None, + Some("Error signing the event creation.".to_string()), + )); + } + }, + }; + + let address = get_address::()?; + let fee = (request.fee() * 1000000.0) as u64; + + let mut program_manager = + ProgramManager::::new(Some(private_key), None, Some(api_client), None)?; + + let mut fee_record_nonce: Option = None; + + if request.event_type() == &EventTypeCommon::Deploy { + let program = match request.inputs().get(0) { + Some(program) => program, + None => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Program not found".to_string(), + "Program not found".to_string(), + )) + } + }; + + let program = match Program::::from_str(program) { + Ok(program) => program, + Err(_) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Program string parsing failure".to_string(), + "Program string parsing failure".to_string(), + )) + } + }; + + program_manager.add_program(&program)?; + + // TODO - Check if dapps take all costs into account for deployment + //let (minimum_deployment_cost, (_storage_cost, _namespace_cost)) = + // program_manager.estimate_deployment_fee::(&program, &private_key)?; + + //let mut fee = minimum_deployment_cost; + //fee += request.fee(); + + let (fee_record, _fee_commitment, fee_id) = match fee_private { + true => { + let (fee_record, fee_commitment, fee_id) = + find_aleo_credits_record_to_spend::(&fee, vec![])?; + + let fee_nonce = fee_record.nonce().to_string(); + fee_record_nonce = Some(fee_nonce); + + (Some(fee_record), Some(fee_commitment), Some(fee_id)) + } + false => (None, None, None), + }; + + let mut pending_deployment_tx = DeploymentPointer::::new( + None, + request.program_id().clone(), + request.fee(), + TransactionState::Processing, + None, + fee_record_nonce, + Local::now(), + None, + None, + ); + + let pending_event_id = pending_deployment_tx.encrypt_and_store(address)?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_event_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + } + + if let Some(fee_id) = fee_id.clone() { + update_record_spent_local::(&fee_id, true)?; + } + + let transaction_id = match program_manager.deploy_program(program.id(), 0, fee_record, None) + { + Ok(tx_id) => tx_id, + Err(_) => { + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, false)?; + } + + pending_deployment_tx.update_failed_deployment( + "Deployment failed, no records were spent.".to_string(), + ); + + let encrypted_failed_deployment = + pending_deployment_tx.to_encrypted_data(address)?; + + update_encrypted_transaction_state_by_id( + &pending_event_id, + &encrypted_failed_deployment.ciphertext, + &encrypted_failed_deployment.nonce, + TransactionState::Failed, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_event_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + } + + return Ok(CreateEventResponse::new( + Some(pending_event_id), + Some(format!("Error deploying program: '{}'", program.id())), + )); + } + }; + + handle_deployment_update_and_encrypted_storage::( + transaction_id, + &pending_event_id, + fee_id, + window, + ) + .await?; + + Ok(CreateEventResponse::new(Some(pending_event_id), None)) + } else { + let mut record_nonces: Vec = vec![]; + + let (input_values, input_nonces, recipient_address, amount) = + parse_inputs::(request.inputs().clone(), &request.function_id().clone())?; + + let (fee_record, _fee_commitment, fee_id) = match fee_private { + true => { + let (fee_record, fee_commitment, fee_id) = + find_aleo_credits_record_to_spend::(&fee, input_nonces.clone())?; + + let fee_nonce = fee_record.nonce().to_string(); + record_nonces.push(fee_nonce); + + (Some(fee_record), Some(fee_commitment), Some(fee_id)) + } + false => (None, None, None), + }; + + record_nonces.extend(input_nonces.clone()); + + let mut pending_transaction = TransactionPointer::::new( + None, + None, + TransactionState::Processing, + None, + Some(request.program_id().clone()), + Some(request.function_id().clone()), + vec![], + record_nonces, + Local::now(), + None, + None, + request.event_type().to_owned(), + amount, + Some(request.fee()), + None, + ); + + let pending_event_id = pending_transaction.encrypt_and_store(address)?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_event_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + } + + // TODO - Update fee to spent and input_nonces to spent + for nonce in input_nonces.clone() { + update_record_spent_local_via_nonce::(&nonce, true)?; + } + + if let Some(fee_id) = fee_id.clone() { + update_record_spent_local::(&fee_id, false)?; + } + println!("=====> INPUTS {:?}", input_values); + let transaction_id = match program_manager.execute_program( + request.program_id().clone(), + request.function_id().clone(), + input_values.iter(), + 0, + fee_record, + None, + ) { + Ok(tx_id) => tx_id, + Err(_) => { + if let Some(fee_id) = fee_id { + update_record_spent_local::(&fee_id, false)?; + } + + for nonce in input_nonces { + update_record_spent_local_via_nonce::(&nonce, false)?; + } + + pending_transaction.update_failed_transaction( + "Transaction execution failed, no records were spent.".to_string(), + ); + + let encrypted_failed_transaction = + pending_transaction.to_encrypted_data(address)?; + + update_encrypted_transaction_state_by_id( + &pending_event_id, + &encrypted_failed_transaction.ciphertext, + &encrypted_failed_transaction.nonce, + TransactionState::Failed, + )?; + + if let Some(window) = window.clone() { + match window.emit("tx_state_change", &pending_event_id) { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting tx_state_change event".to_string(), + "Error emitting transaction state".to_string(), + )); + } + }; + } + + return Ok(CreateEventResponse::new( + Some(pending_event_id), + Some(format!( + "Error executing program: '{}' function: '{}' ", + request.program_id(), + request.function_id() + )), + )); + } + }; + + match recipient_address { + Some(recipient_address) => { + handle_encrypted_storage_and_message::( + transaction_id, + recipient_address, + &pending_event_id, + None, + fee_id, + true, + window, + ) + .await? + } + None => { + handle_transaction_update_and_encrypted_storage::( + transaction_id, + &pending_event_id, + fee_id, + window, + ) + .await? + } + } + + Ok(CreateEventResponse::new(Some(pending_event_id), None)) + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn get_records(request: GetRecordsRequest) -> AvailResult { + let network = get_network()?; + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => match get_records_raw::(request) { + Ok((records, page_count)) => { + Ok(GetRecordsResponse::new(records, Some(page_count), None)) + } + Err(error) => Ok(GetRecordsResponse::new( + vec![], + None, + Some(error.external_msg), + )), + }, + _ => match get_records_raw::(request) { + Ok((records, page_count)) => { + Ok(GetRecordsResponse::new(records, Some(page_count), None)) + } + Err(error) => Ok(GetRecordsResponse::new( + vec![], + None, + Some(error.external_msg), + )), + }, //SupportedNetworks::Mainnet => get_records_raw::(request), + } +} + +pub fn get_records_raw( + request: GetRecordsRequest, +) -> AvailResult<(Vec, i32)> { + // TODO - return page count + + let page_count = get_page_count_for_filter(request.clone())?; + let (pointers, ids) = get_record_pointers::(request)?; + + let records_with_plaintext = pointers + .iter() + .zip(ids.iter()) + .map(|(pointer, id)| { + RecordWithPlaintext::from_record_pointer::(pointer.clone(), id.clone()) + }) + .collect::>>()?; + + Ok((records_with_plaintext, page_count)) +} + +#[tauri::command(rename_all = "snake_case")] +pub fn sign(request: SignatureRequest, window: Window) -> AvailResult { + let network = get_network()?; + + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => { + match sign_message::(&request.get_message(), None) { + Ok((signature, message_field)) => Ok(SignatureResponse::new( + Some(signature.to_string()), + Some(message_field.to_string()), + None, + )), + Err(e) => { + if e.error_type == AvailErrorType::Unauthorized { + match window.emit("reauthenticate", "sign") { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting reauthentication event".to_string(), + "Error emitting reauthentication state".to_string(), + )); + } + }; + } + Ok(SignatureResponse::new( + None, + None, + Some("Signing Failed".to_string()), + )) + } + } + } + _ => match sign_message::(&request.get_message(), None) { + Ok((signature, message_field)) => Ok(SignatureResponse::new( + Some(signature.to_string()), + Some(message_field.to_string()), + None, + )), + Err(e) => { + if e.error_type == AvailErrorType::Unauthorized { + match window.emit("reauthenticate", "sign") { + Ok(_) => {} + Err(e) => { + return Err(AvailError::new( + AvailErrorType::Internal, + "Error emitting reauthentication event".to_string(), + "Error emitting reauthentication state".to_string(), + )); + } + }; + } + Ok(SignatureResponse::new( + None, + None, + Some("Signing Failed".to_string()), + )) + } + }, + //SupportedNetworks::Mainnet => decrypt_record_raw::(ciphertext), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub fn verify(message: &str, address: &str, signature: &str) -> AvailResult { + let network = get_network()?; + + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => verify_signature::(message, address, signature), + _ => verify_signature::(message, address, signature), + } +} + +fn verify_signature( + message: &str, + address: &str, + signature: &str, +) -> AvailResult { + let signature = Signature::::from_str(signature)?; + let address = Address::::from_str(address)?; + + let msg_bits = utf8_string_to_bits(message); + let msg_field = N::hash_bhp512(&msg_bits)?; + let msg = field_to_fields(&msg_field)?; + + let result = signature.verify(&address, &msg); + + Ok(result) +} + +#[tauri::command(rename_all = "snake_case")] +pub fn decrypt_records(request: DecryptRequest) -> AvailResult { + let network = get_network()?; + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => match decrypt_records_raw::(request.ciphertexts) { + Ok(plaintexts) => Ok(DecryptResponse::new(plaintexts, None)), + Err(error) => Ok(DecryptResponse::new(vec![], Some(error.external_msg))), + }, + _ => match decrypt_records_raw::(request.ciphertexts) { + Ok(plaintexts) => Ok(DecryptResponse::new(plaintexts, None)), + Err(error) => Ok(DecryptResponse::new(vec![], Some(error.external_msg))), + }, //SupportedNetworks::Mainnet => decrypt_record_raw::(ciphertext), + } +} + +pub fn decrypt_records_raw(ciphertext: Vec) -> AvailResult> { + let view_key = VIEWSESSION.get_instance::()?; + let records = ciphertext + .iter() + .map(|ciphertext| { + let record_ciphertext = Record::>::from_str(ciphertext)?; + let record = match record_ciphertext.decrypt(&view_key) { + Ok(record) => record, + Err(_) => { + return Err(AvailError::new( + AvailErrorType::SnarkVm, + format!("Decryption Failed on record: {}", ciphertext), + format!("Decryption Failed on record: {}", ciphertext), + )) + } + }; + Ok(record.to_string()) + }) + .collect::>>()?; + + Ok(records) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn get_events(request: GetEventsRequest) -> AvailResult { + let network = get_network()?; + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => match get_events_raw::(request) { + Ok(events) => Ok(GetEventsResponse::new(events, None, None)), + Err(error) => Ok(GetEventsResponse::new( + vec![], + None, + Some(error.external_msg), + )), + }, + _ => match get_events_raw::(request) { + Ok(events) => Ok(GetEventsResponse::new(events, None, None)), + Err(error) => Ok(GetEventsResponse::new( + vec![], + None, + Some(error.external_msg), + )), + }, + //SupportedNetworks::Mainnet => get_events_raw::(request), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_event(request: GetEventRequest) -> AvailResult { + let network = get_network()?; + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => match get_event_raw::(&request.id) { + Ok(event) => Ok(GetEventResponse::new(Some(event), None)), + Err(error) => Ok(GetEventResponse::new(None, Some(error.external_msg))), + }, + _ => match get_event_raw::(&request.id) { + Ok(event) => Ok(GetEventResponse::new(Some(event), None)), + Err(error) => Ok(GetEventResponse::new(None, Some(error.external_msg))), + }, + //SupportedNetworks::Mainnet => get_event_raw::(request), + } +} + +/* --Avail Events-- */ +#[tauri::command(rename_all = "snake_case")] +pub fn get_avail_events(request: GetEventsRequest) -> AvailResult> { + let network = get_network()?; + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => get_avail_events_raw::(request), + _ => get_avail_events_raw::(request), //SupportedNetworks::Mainnet => get_events_raw::(request), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_succinct_avail_events( + request: GetEventsRequest, +) -> AvailResult> { + let network = get_network()?; + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => get_succinct_avail_events_raw::(request), + _ => get_succinct_avail_events_raw::(request), + } + //SupportedNetworks::Mainnet => get_events_raw::(request), +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_succinct_avail_event(id: &str) -> AvailResult { + let network = get_network()?; + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => get_succinct_avail_event_raw::(id), + _ => get_succinct_avail_event_raw::(id), + } + //SupportedNetworks::Mainnet => get_event_raw::(request), +} + +#[tauri::command(rename_all = "snake_case")] +pub fn get_avail_event(id: &str) -> AvailResult { + let network = get_network()?; + match SupportedNetworks::from_str(&network)? { + SupportedNetworks::Testnet3 => get_avail_event_raw::(id), + _ => get_avail_event_raw::(id), //SupportedNetworks::Mainnet => get_event_raw::(request), + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::api::encrypted_data::delete_all_server_storage; + + use crate::models::storage::languages::Languages; + use crate::models::{ + transfer::TransferRequest, + wallet_connect::records::{RecordFilterType, RecordsFilter}, + }; + + use crate::services::account::key_management::key_controller::KeyController; + + #[cfg(target_os = "linux")] + use crate::services::account::key_management::key_controller::linuxKeyController; + #[cfg(target_os = "macos")] + use crate::services::account::key_management::key_controller::macKeyController; + #[cfg(target_os = "windows")] + use crate::services::account::key_management::key_controller::windowsKeyController; + + use crate::services::local_storage::encrypted_data::{ + get_encrypted_data_by_flavour, initialize_encrypted_data_table, + }; + use crate::services::local_storage::persistent_storage::initial_user_preferences; + use crate::services::local_storage::utils::sign_message_w_key; + use crate::services::local_storage::{ + encrypted_data::drop_encrypted_data_table, persistent_storage::delete_user_preferences, + }; + use crate::services::record_handling::transfer::transfer_raw; + + use avail_common::models::encrypted_data::EncryptedDataTypeCommon; + use avail_common::{models::constants::*, models::encrypted_data::EventTypeCommon}; + use snarkvm::prelude::{Address, FromStr, Identifier, PrivateKey, Testnet3, ViewKey}; + + use crate::services::account::generation::import_wallet; + + /* + #[tokio::test] + async fn test_setup_prerequisites() { + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + + drop_encrypted_data_table().unwrap(); + delete_user_preferences().unwrap(); + // initialize the user preferences + + import_wallet( + Some("Satoshi".to_string()), + STRONG_PASSWORD.to_string(), + false, + &pk.to_string(), + false, + Languages::English, + ) + .await + .unwrap(); + + let address = get_address::().unwrap(); + + let request = TransferRequest::new( + address.to_string(), + 10000000, + Some("Private Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::Private, + false, + 300000, + "credits".to_string(), + ); + + transfer_raw::(request, None).await.unwrap(); + } + */ + + fn test_setup_prerequisites() -> PrivateKey { + // no records transferred as set up. + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let view_key = ViewKey::::try_from(&pk).unwrap(); + + drop_encrypted_data_table().unwrap(); + + delete_user_preferences().unwrap(); + // initialize the user preferences + initial_user_preferences( + false, + None, + None, + false, + false, + view_key.to_address().to_string(), + Languages::English, + ) + .unwrap(); + + initialize_encrypted_data_table().unwrap(); + + VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); + + return pk; + } + + #[test] + fn test_get_balance() { + //change to what os you are testing on + //test_setup_prerequisites_mac(); + VIEWSESSION + .set_view_session("AViewKey1pViDeDV8dT1yTCdzU6ojxh8GdFDadSasRpk6mZdyz8mh") + .unwrap(); + + println!( + " <<<<<<<<<<<<<< Testing get_balance() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>" + ); + let request = BalanceRequest::new(Some("credits"), None); + let res = get_balance(request).unwrap(); + println!("res: {:?}", res); + } + + #[test] + fn test_get_records() { + test_setup_prerequisites(); + + println!( + " <<<<<<<<<<<<<< Testing get_records() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>" + ); + let records_filter = RecordsFilter::new( + vec!["credits.aleo".to_string()], + None, + RecordFilterType::All, + Some("credits.record".to_string()), + ); + + let request = GetRecordsRequest::new(None, Some(records_filter), None); + let (res, _page_count) = get_records_raw::(request).unwrap(); + // println!("res: {:?}", res); + + println!("page_count: {:?}", _page_count); + + for value in res.into_iter() { + println!("res: {:?}", value); + } + } + + #[tokio::test] + async fn test_request_create_event() { + println!(" <<<<<<<<<<<<<<< Testing request_create_event() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>"); + /* -- Has to be called here cause has to await-- */ + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + let ext = Identifier::::from_str("test").unwrap(); + + let key_controller = { + #[cfg(target_os = "linux")] + { + linuxKeyController {} + } + + #[cfg(target_os = "macos")] + { + macKeyController {} + } + + #[cfg(target_os = "windows")] + { + windowsKeyController {} + } + }; + + key_controller + .delete_key(Some(STRONG_PASSWORD), ext) + .unwrap(); + + delete_all_server_storage().await.unwrap(); + drop_encrypted_data_table().unwrap(); + + delete_user_preferences().unwrap(); + // initialize the user preferences + + import_wallet( + Some("Satoshi".to_string()), + STRONG_PASSWORD.to_string(), + false, + &pk.to_string(), + false, + Languages::English, + ) + .await + .unwrap(); + + let address = get_address::().unwrap(); + + let request = TransferRequest::new( + address.to_string(), + 10000000, + Some("Private Transfer Test".to_string()), + Some(STRONG_PASSWORD.to_string()), + TransferType::Private, + false, + 300000, + "credits".to_string(), + ); + + transfer_raw::(request, None).await.unwrap(); + /* --SETUP COMPLETE */ + + let recipient = Address::::from_str(TESTNET3_ADDRESS).unwrap(); + let (record, _, _) = find_aleo_credits_record_to_spend::(&10000, vec![]).unwrap(); + + let program_id: &str = "credits.aleo"; + let function_id: &str = "transfer_private"; + let fee = 300000u64; + let inputs: Vec = [ + record.to_string(), + recipient.to_string(), + "10000u64".to_string(), + ] + .to_vec(); + + let request = CreateEventRequest::new( + None, + EventTypeCommon::Execute, + program_id.to_string(), + function_id.to_string(), + fee as f64 / 1000000.0, + inputs, + ); + + PASS.set_pass_session(STRONG_PASSWORD).unwrap(); + + let result_create_event = + request_create_event_raw::(request, false, None) + .await + .unwrap(); + println!("res: {:?}", result_create_event); + } + + #[test] + fn test_decrypt() { + println!( + " <<<<<<<<<<<<<<< Testing decrypt() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>" + ); + + test_setup_prerequisites(); + + let records_filter = RecordsFilter::new( + vec!["credits.aleo".to_string()], + None, + RecordFilterType::Unspent, + Some("credits.record".to_string()), + ); + + let request = GetRecordsRequest::new(None, Some(records_filter), None); + let (res, _page_count) = get_records_raw::(request).unwrap(); + + let mut ciphertexts: Vec = vec![]; + + for value in res.into_iter() { + ciphertexts.push(value.record.ciphertext); + } + + let request = DecryptRequest::new(ciphertexts); + let res = decrypt_records(request).unwrap(); + + println!("Result: {:?}", res); + } + + #[tokio::test] + async fn get_events_test() { + println!( + " <<<<<<<<<<<<<<< Testing get_events() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>" + ); + + test_setup_prerequisites(); + + VIEWSESSION + .set_view_session("AViewKey1pViDeDV8dT1yTCdzU6ojxh8GdFDadSasRpk6mZdyz8mh") + .unwrap(); + + let request = GetEventsRequest { + filter: None, + page: None, + }; + + let res = get_events(request).await.unwrap(); + + println!("Result: {:?}", res); + } + + #[test] + fn get_event_test() { + println!( + " <<<<<<<<<<<<<<< Testing get_event() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>" + ); + + test_setup_prerequisites(); + + let encrypted_transaction = + get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transaction).unwrap(); + + let request = GetEventRequest { + id: encrypted_transaction[0].id.unwrap().to_string(), + address: None, + }; + + let res = get_event(request).unwrap(); + + println!("Result: {:?}", res); + } + + #[test] + fn test_verify_signature() { + let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); + + let message = "Hello World"; + + let (signature, _) = sign_message_w_key::(message, &pk).unwrap(); + + let address = Address::::try_from(&pk).unwrap(); + + let res = verify(message, &address.to_string(), &signature.to_string()).unwrap(); + + assert_eq!(res, true); + } + + #[test] + fn test_fee_f64() { + let fee = 0.3; + let fee = (fee * 1000000.0) as u64; + println!("fee: {:?}", fee); + + let fee_x = 300000u64; + //divide fee_x in a way that it becomes 0.3 + let fee_x = (fee_x as f64) / 1000000.0; + println!("fee_x: {:?}", fee_x); + } +} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json new file mode 100644 index 00000000..cd0634cc --- /dev/null +++ b/src-tauri/tauri.conf.json @@ -0,0 +1,56 @@ +{ + "productName": "Avail", + "identifier": "com.avail.wallet", + "build": { + "beforeDevCommand": "npm i && npm run dev", + "beforeBuildCommand": "npm i && npm run build", + "devUrl": "http://localhost:1420", + "frontendDist": "dist" + }, + "bundle": { + "active": true, + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], + "targets": "all" + }, + "plugins": { + "updater": { + "endpoints": [ + "https://api.avail.global/release/latest" + ], + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDRDM0Y4QzExNTM2REEyQUMKUldTc29tMVRFWXcvVEQ0MDRqdHVKZjU4MkxjUUtRM3JvZTc0eE1ZZGI2YmZrRWVFQVlKTk1MZFMK" + }, + "deep-link": { + "domains": [ + { + "host": "com.avail.wallet", + "pathPrefix": [ + "avail://" + ] + } + ] + } + }, + "app": { + "security": { + "csp": null + }, + "withGlobalTauri": true, + "windows": [ + { + "fullscreen": false, + "resizable": true, + "title": "Avail", + "width": 1125, + "height": 800, + "minWidth": 843.75, + "minHeight": 600 + } + ] + } +} diff --git a/src-tauri/tauri.windows.conf.json b/src-tauri/tauri.windows.conf.json new file mode 100644 index 00000000..e18a62d7 --- /dev/null +++ b/src-tauri/tauri.windows.conf.json @@ -0,0 +1,7 @@ +{ + "build": { + "beforeDevCommand": "cd .\\frontend\\ & npm i & npm run dev", + "beforeBuildCommand": "cd .\\frontend\\ & npm i & npm run build", + "frontendDist": "..\\frontend\\dist" + } +} \ No newline at end of file From 67df3d8f27a2d61cf9f449d9c7719fd429505fd0 Mon Sep 17 00:00:00 2001 From: girogio Date: Tue, 20 Feb 2024 09:47:52 +0100 Subject: [PATCH 2/3] Project restructure --- .github/workflows/{tauri.yml => release.yml} | 16 +- .github/workflows/rust-clippy.yml | 1 + .github/workflows/test.yml | 11 +- .gitignore | 31 + backend/.gitignore | 4 - backend/Cargo.lock | 7561 ----------------- backend/Cargo.toml | 94 - backend/build.rs | 3 - backend/capabilities/capabilities.toml | 20 - backend/icons/128x128.png | Bin 2837 -> 0 bytes backend/icons/128x128@2x.png | Bin 2837 -> 0 bytes backend/icons/32x32.png | Bin 879 -> 0 bytes backend/icons/icon.icns | Bin 3890 -> 0 bytes backend/icons/icon.ico | Bin 4286 -> 0 bytes backend/icons/icon.png | Bin 2837 -> 0 bytes backend/package-lock.json | 6 - backend/src/api.rs | 6 - backend/src/api/aleo_client.rs | 121 - backend/src/api/client.rs | 100 - backend/src/api/encrypted_data.rs | 704 -- backend/src/api/fee.rs | 176 - backend/src/api/tokens.rs | 52 - backend/src/api/user.rs | 259 - backend/src/helpers.rs | 3 - backend/src/helpers/upgrade.rs | 58 - backend/src/helpers/utils.rs | 67 - backend/src/helpers/validation.rs | 145 - backend/src/lib.rs | 102 - backend/src/main.rs | 13 - backend/src/models.rs | 9 - backend/src/models/account.rs | 24 - backend/src/models/auth.rs | 134 - backend/src/models/event.rs | 346 - backend/src/models/event_payloads.rs | 10 - backend/src/models/pointers.rs | 5 - backend/src/models/pointers/deployment.rs | 377 - backend/src/models/pointers/message.rs | 115 - backend/src/models/pointers/record.rs | 255 - backend/src/models/pointers/transaction.rs | 660 -- backend/src/models/pointers/transition.rs | 357 - backend/src/models/storage/encryption.rs | 48 - backend/src/models/storage/languages.rs | 84 - backend/src/models/storage/mod.rs | 3 - backend/src/models/storage/persistent.rs | 132 - backend/src/models/transfer.rs | 83 - backend/src/models/wallet.rs | 269 - backend/src/models/wallet_connect.rs | 6 - backend/src/models/wallet_connect/balance.rs | 82 - .../src/models/wallet_connect/create_event.rs | 80 - backend/src/models/wallet_connect/decrypt.rs | 24 - backend/src/models/wallet_connect/deploy.rs | 1 - .../src/models/wallet_connect/get_event.rs | 123 - backend/src/models/wallet_connect/records.rs | 203 - backend/src/models/wallet_connect/sign.rs | 55 - backend/src/services.rs | 6 - backend/src/services/README.md | 43 - backend/src/services/account.rs | 4 - backend/src/services/account/generation.rs | 159 - .../src/services/account/key_management.rs | 2 - .../account/key_management/android.rs | 719 -- .../account/key_management/desktop.rs | 229 - .../services/account/key_management/iOS.rs | 244 - .../account/key_management/key_controller.rs | 207 - .../src/services/account/phrase_recovery.rs | 96 - .../src/services/account/shard_recovery.rs | 1 - backend/src/services/account/utils.rs | 76 - backend/src/services/authentication.rs | 7 - .../src/services/authentication/android.rs | 39 - backend/src/services/authentication/ios.rs | 37 - .../src/services/authentication/session.rs | 327 - backend/src/services/local_storage.rs | 6 - .../services/local_storage/encrypted_data.rs | 794 -- .../local_storage/persistent_storage.rs | 489 -- backend/src/services/local_storage/session.rs | 2 - .../local_storage/session/password.rs | 75 - .../services/local_storage/session/view.rs | 59 - .../src/services/local_storage/storage_api.rs | 6 - .../local_storage/storage_api/deployment.rs | 147 - .../local_storage/storage_api/event.rs | 539 -- .../local_storage/storage_api/records.rs | 641 -- .../local_storage/storage_api/transaction.rs | 471 - .../local_storage/storage_api/transition.rs | 123 - backend/src/services/local_storage/tokens.rs | 328 - backend/src/services/local_storage/utils.rs | 345 - backend/src/services/record_handling.rs | 5 - .../record_handling/decrypt_transition.rs | 668 -- backend/src/services/record_handling/docs.md | 4 - .../src/services/record_handling/records.rs | 800 -- backend/src/services/record_handling/sync.rs | 805 -- .../src/services/record_handling/transfer.rs | 1413 --- backend/src/services/record_handling/utils.rs | 2092 ----- backend/src/services/records.rs | 127 - backend/src/services/wallet_connect_api.rs | 1011 --- backend/tauri.conf.json | 56 - backend/tauri.windows.conf.json | 7 - frontend/.gitignore | 31 - frontend/package-lock.json | 6446 -------------- frontend/index.html => index.html | 0 package-lock.json | 6444 +++++++++++++- frontend/package.json => package.json | 4 +- {frontend/public => public}/a-icon.svg | 0 .../locales/de/translation.json | 0 .../locales/en/translation.json | 0 .../locales/es/translation.json | 0 .../locales/et/translation.json | 0 .../locales/it/translation.json | 0 .../locales/ja/translation.json | 0 .../locales/lt/translation.json | 0 .../locales/lv/translation.json | 0 .../locales/nl/translation.json | 0 .../locales/ru/translation.json | 0 .../locales/tr/translation.json | 0 .../locales/zh-CN/translation.json | 0 .../locales/zh-TW/translation.json | 0 {frontend/public => public}/tauri.svg | 0 {frontend/public => public}/vite.svg | 0 .../wallet-connect.html | 0 .../wallet-connect-screens/wallet-connect.js | 0 .../public => public}/wc-images/balance.svg | 0 .../public => public}/wc-images/connect.svg | 0 .../public => public}/wc-images/decrypt.svg | 0 .../public => public}/wc-images/deploy.svg | 0 .../public => public}/wc-images/execute.svg | 0 .../public => public}/wc-images/sign.svg | 0 .../wc-images/transactions.svg | 0 {frontend/public => public}/wc-images/tx.svg | 0 {frontend/src => src}/App.tsx | 0 {frontend/src => src}/assets/dapps/ans.svg | 0 {frontend/src => src}/assets/dapps/arcane.svg | 0 {frontend/src => src}/assets/dapps/dapps.ts | 0 .../src => src}/assets/dapps/shadowfi.png | Bin .../src => src}/assets/dapps/staking.png | Bin .../assets/fonts/DMsans/DMSans-Bold.ttf | Bin .../assets/fonts/DMsans/DMSans-ExtraBold.ttf | Bin .../assets/fonts/DMsans/DMSans-ExtraLight.ttf | Bin .../assets/fonts/DMsans/DMSans-Italic.ttf | Bin .../assets/fonts/DMsans/DMSans-Light.ttf | Bin .../assets/fonts/DMsans/DMSans-Medium.ttf | Bin .../assets/fonts/DMsans/DMSans-Regular.ttf | Bin .../assets/fonts/DMsans/DMSans-SemiBold.ttf | Bin .../assets/fonts/DMsans/DMSans-Thin.ttf | Bin .../assets/icons/contracts/house-loan.svg | 0 .../assets/icons/contracts/loan-icon.svg | 0 .../assets/icons/contracts/rent-icon.svg | 0 .../assets/icons/contracts/sale-icon.svg | 0 .../assets/icons/contracts/service-icon.svg | 0 .../assets/icons/contracts/web-dev-icon.svg | 0 .../assets/icons/hub-icon-green.svg | 0 .../src => src}/assets/icons/hub-icon.svg | 0 .../src => src}/assets/icons/notification.svg | 0 .../src => src}/assets/icons/qr-code.svg | 0 .../src => src}/assets/icons/tokens/aleo.svg | 0 .../src => src}/assets/icons/tokens/usdt.svg | 0 .../assets/images/backgrounds/sign-up-bg.jpeg | Bin .../assets/images/backgrounds/sign-up-bg.svg | 0 .../src => src}/assets/images/backup.svg | 0 .../src => src}/assets/images/login-dalle.svg | 0 .../src => src}/assets/images/tokens/ALEO.svg | 0 .../src => src}/assets/images/tokens/USDC.svg | 0 {frontend/src => src}/assets/logo/a-icon.svg | 0 .../assets/logo/desktop-full-logo.svg | 0 .../src => src}/assets/logo/full-logo.svg | 0 .../notification-icons/nannouncement.svg | 0 .../assets/notification-icons/ncontract.svg | 0 .../assets/notification-icons/nheart.svg | 0 .../notification-icons/nloan_accepted.svg | 0 .../notification-icons/nloan_request.svg | 0 .../assets/notification-icons/npayment.svg | 0 {frontend/src => src}/assets/react.svg | 0 .../src => src}/browser/nova_browser.tsx | 0 .../components/account/details.tsx | 0 .../components/account/profile-header.tsx | 0 .../src => src}/components/assets/asset.tsx | 0 .../components/assets/asset_drawer.tsx | 0 .../components/assets/balances.tsx | 0 .../components/backup/backup_dialog.tsx | 0 {frontend/src => src}/components/balance.tsx | 0 .../src => src}/components/buttons/back.tsx | 0 .../src => src}/components/buttons/cta.tsx | 0 .../components/buttons/home_options.tsx | 0 .../components/buttons/login-button.tsx | 0 .../components/buttons/secure-button.tsx | 0 .../components/buttons/settings-button.tsx | 0 .../components/buttons/sign-up-button.tsx | 0 .../components/buttons/transfer_cta.tsx | 0 .../components/chat/add_contact.tsx | 0 .../src => src}/components/chat/friend.tsx | 0 .../src => src}/components/chat/message.tsx | 0 .../components/chat/message_bar.tsx | 0 .../components/chat/new_transfer.tsx | 0 .../src => src}/components/chat/room.tsx | 0 .../components/contracts/contractItem.tsx | 0 .../contracts/contract_bottom_bar.tsx | 0 .../src => src}/components/dApps/dapp.tsx | 0 .../src => src}/components/dialogs/delete.tsx | 0 .../components/dialogs/disable_backup.tsx | 0 .../dialogs/keys/get_private_key.tsx | 0 .../dialogs/keys/get_seed_phrase.tsx | 0 .../dialogs/keys/get_viewing_key.tsx | 0 .../src => src}/components/dialogs/logout.tsx | 0 .../src => src}/components/dialogs/reauth.tsx | 0 .../components/dialogs/receive.tsx | 0 .../components/dialogs/scan_reauth.tsx | 0 .../components/dialogs/transfer.tsx | 0 .../components/dialogs/username.tsx | 0 .../src => src}/components/events/event.tsx | 0 .../components/events/event_drawer.tsx | 0 .../components/events/explorer.tsx | 0 .../components/events/transition.tsx | 0 .../src => src}/components/header/appbar.tsx | 0 .../components/header/chat_header.tsx | 0 .../components/header/contract_header.tsx | 0 .../src => src}/components/header/header.tsx | 0 .../components/header/simple_appbar.tsx | 0 .../components/header/transfer_header.tsx | 0 .../src => src}/components/icons/received.tsx | 0 .../src => src}/components/icons/sent.tsx | 0 .../src => src}/components/loadingScreen.tsx | 0 .../src => src}/components/menu/options.tsx | 0 {frontend/src => src}/components/nft.tsx | 0 .../components/notifications/notification.tsx | 0 .../components/notifications/slider.tsx | 0 .../src => src}/components/searchabar.tsx | 0 .../components/select/language.tsx | 0 .../components/select/seed_length.tsx | 0 .../components/settings/general.tsx | 0 {frontend/src => src}/components/sidebar.tsx | 0 .../components/snackbars/alerts.tsx | 0 .../components/switch/privacy_toggle.tsx | 0 .../components/textfields/white-hue.tsx | 0 .../components/transfer/token_dropdown.tsx | 0 .../components/transfer/transfer_box.tsx | 0 .../components/typography/typography.tsx | 0 .../src => src}/context/EventsContext.tsx | 0 {frontend/src => src}/context/ScanContext.tsx | 0 .../src => src}/context/WalletConnect.tsx | 0 {frontend/src => src}/i18next-config.ts | 0 {frontend/src => src}/index.css | 0 {frontend/src => src}/main.tsx | 0 .../services/authentication/auth.ts | 0 .../services/authentication/register.ts | 0 .../src => src}/services/events/get_events.ts | 0 .../src => src}/services/keychain/keychain.ts | 0 {frontend/src => src}/services/nfts/fetch.ts | 0 .../src => src}/services/recovery/phrase.ts | 0 .../src => src}/services/scans/backup.ts | 0 .../src => src}/services/scans/blocks.ts | 0 .../services/scans/encrypted_messages.ts | 0 .../src => src}/services/states/utils.ts | 0 .../src => src}/services/storage/keys.ts | 0 .../services/storage/localStorage.ts | 0 .../services/storage/persistent.ts | 0 .../services/tokens/get_balance.ts | 0 .../src => src}/services/tokens/get_tokens.ts | 0 .../services/transfer/inclusion.ts | 0 .../services/transfer/transfers.ts | 0 .../src => src}/services/util/functions.ts | 0 {frontend/src => src}/services/util/open.ts | 0 {frontend/src => src}/services/util/sign.ts | 0 .../services/wallet-connect/AleoWallet.ts | 0 .../services/wallet-connect/SessionInfo.ts | 0 .../services/wallet-connect/WCTypes.ts | 0 .../wallet-connect/WalletConnectManager.ts | 0 {frontend/src => src}/styles/animations.css | 0 {frontend/src => src}/styles/shapes.css | 0 {frontend/src => src}/styles/theme.ts | 0 {frontend/src => src}/types/assets/asset.ts | 0 {frontend/src => src}/types/auth.ts | 0 .../src => src}/types/avail-events/event.ts | 0 {frontend/src => src}/types/chat/messages.ts | 0 {frontend/src => src}/types/chat/room.ts | 0 .../src => src}/types/contracts/service.ts | 0 {frontend/src => src}/types/errors.ts | 0 {frontend/src => src}/types/events.ts | 0 {frontend/src => src}/types/languages.ts | 0 {frontend/src => src}/types/nfts/nft.ts | 0 {frontend/src => src}/types/notification.tsx | 0 .../types/transfer_props/tokens.ts | 0 .../src => src}/types/user_preferences.ts | 0 .../src => src}/views-desktop/activity.tsx | 0 .../src => src}/views-desktop/browser.tsx | 0 .../src => src}/views-desktop/entrypoint.tsx | 0 .../views-desktop/home-desktop.tsx | 0 {frontend/src => src}/views-desktop/login.tsx | 0 {frontend/src => src}/views-desktop/nft.tsx | 0 {frontend/src => src}/views-desktop/oops.tsx | 0 .../views-desktop/privacy-policy.tsx | 0 .../src => src}/views-desktop/recovery.tsx | 0 .../src => src}/views-desktop/register.tsx | 0 .../views-desktop/reusable/bottom-nav.tsx | 0 .../views-desktop/reusable/layout.tsx | 0 .../src => src}/views-desktop/seedphrase.tsx | 0 {frontend/src => src}/views-desktop/send.tsx | 0 .../src => src}/views-desktop/settings.tsx | 0 .../views-desktop/terms-and-conditions.tsx | 0 .../src => src}/views-desktop/verify.tsx | 0 {frontend/src => src}/vite-env.d.ts | 0 frontend/tsconfig.json => tsconfig.json | 0 .../tsconfig.node.json => tsconfig.node.json | 0 frontend/vite.config.ts => vite.config.ts | 0 300 files changed, 6482 insertions(+), 32690 deletions(-) rename .github/workflows/{tauri.yml => release.yml} (89%) delete mode 100644 backend/.gitignore delete mode 100644 backend/Cargo.lock delete mode 100644 backend/Cargo.toml delete mode 100644 backend/build.rs delete mode 100644 backend/capabilities/capabilities.toml delete mode 100644 backend/icons/128x128.png delete mode 100644 backend/icons/128x128@2x.png delete mode 100644 backend/icons/32x32.png delete mode 100644 backend/icons/icon.icns delete mode 100644 backend/icons/icon.ico delete mode 100644 backend/icons/icon.png delete mode 100644 backend/package-lock.json delete mode 100644 backend/src/api.rs delete mode 100644 backend/src/api/aleo_client.rs delete mode 100644 backend/src/api/client.rs delete mode 100644 backend/src/api/encrypted_data.rs delete mode 100644 backend/src/api/fee.rs delete mode 100644 backend/src/api/tokens.rs delete mode 100644 backend/src/api/user.rs delete mode 100644 backend/src/helpers.rs delete mode 100644 backend/src/helpers/upgrade.rs delete mode 100644 backend/src/helpers/utils.rs delete mode 100644 backend/src/helpers/validation.rs delete mode 100644 backend/src/lib.rs delete mode 100644 backend/src/main.rs delete mode 100644 backend/src/models.rs delete mode 100644 backend/src/models/account.rs delete mode 100644 backend/src/models/auth.rs delete mode 100644 backend/src/models/event.rs delete mode 100644 backend/src/models/event_payloads.rs delete mode 100644 backend/src/models/pointers.rs delete mode 100644 backend/src/models/pointers/deployment.rs delete mode 100644 backend/src/models/pointers/message.rs delete mode 100644 backend/src/models/pointers/record.rs delete mode 100644 backend/src/models/pointers/transaction.rs delete mode 100644 backend/src/models/pointers/transition.rs delete mode 100644 backend/src/models/storage/encryption.rs delete mode 100644 backend/src/models/storage/languages.rs delete mode 100644 backend/src/models/storage/mod.rs delete mode 100644 backend/src/models/storage/persistent.rs delete mode 100644 backend/src/models/transfer.rs delete mode 100644 backend/src/models/wallet.rs delete mode 100644 backend/src/models/wallet_connect.rs delete mode 100644 backend/src/models/wallet_connect/balance.rs delete mode 100644 backend/src/models/wallet_connect/create_event.rs delete mode 100644 backend/src/models/wallet_connect/decrypt.rs delete mode 100644 backend/src/models/wallet_connect/deploy.rs delete mode 100644 backend/src/models/wallet_connect/get_event.rs delete mode 100644 backend/src/models/wallet_connect/records.rs delete mode 100644 backend/src/models/wallet_connect/sign.rs delete mode 100644 backend/src/services.rs delete mode 100644 backend/src/services/README.md delete mode 100644 backend/src/services/account.rs delete mode 100644 backend/src/services/account/generation.rs delete mode 100644 backend/src/services/account/key_management.rs delete mode 100644 backend/src/services/account/key_management/android.rs delete mode 100644 backend/src/services/account/key_management/desktop.rs delete mode 100644 backend/src/services/account/key_management/iOS.rs delete mode 100644 backend/src/services/account/key_management/key_controller.rs delete mode 100644 backend/src/services/account/phrase_recovery.rs delete mode 100644 backend/src/services/account/shard_recovery.rs delete mode 100644 backend/src/services/account/utils.rs delete mode 100644 backend/src/services/authentication.rs delete mode 100644 backend/src/services/authentication/android.rs delete mode 100644 backend/src/services/authentication/ios.rs delete mode 100644 backend/src/services/authentication/session.rs delete mode 100644 backend/src/services/local_storage.rs delete mode 100644 backend/src/services/local_storage/encrypted_data.rs delete mode 100644 backend/src/services/local_storage/persistent_storage.rs delete mode 100644 backend/src/services/local_storage/session.rs delete mode 100644 backend/src/services/local_storage/session/password.rs delete mode 100644 backend/src/services/local_storage/session/view.rs delete mode 100644 backend/src/services/local_storage/storage_api.rs delete mode 100644 backend/src/services/local_storage/storage_api/deployment.rs delete mode 100644 backend/src/services/local_storage/storage_api/event.rs delete mode 100644 backend/src/services/local_storage/storage_api/records.rs delete mode 100644 backend/src/services/local_storage/storage_api/transaction.rs delete mode 100644 backend/src/services/local_storage/storage_api/transition.rs delete mode 100644 backend/src/services/local_storage/tokens.rs delete mode 100644 backend/src/services/local_storage/utils.rs delete mode 100644 backend/src/services/record_handling.rs delete mode 100644 backend/src/services/record_handling/decrypt_transition.rs delete mode 100644 backend/src/services/record_handling/docs.md delete mode 100644 backend/src/services/record_handling/records.rs delete mode 100644 backend/src/services/record_handling/sync.rs delete mode 100644 backend/src/services/record_handling/transfer.rs delete mode 100644 backend/src/services/record_handling/utils.rs delete mode 100644 backend/src/services/records.rs delete mode 100644 backend/src/services/wallet_connect_api.rs delete mode 100644 backend/tauri.conf.json delete mode 100644 backend/tauri.windows.conf.json delete mode 100644 frontend/.gitignore delete mode 100644 frontend/package-lock.json rename frontend/index.html => index.html (100%) rename frontend/package.json => package.json (97%) rename {frontend/public => public}/a-icon.svg (100%) rename {frontend/public => public}/locales/de/translation.json (100%) rename {frontend/public => public}/locales/en/translation.json (100%) rename {frontend/public => public}/locales/es/translation.json (100%) rename {frontend/public => public}/locales/et/translation.json (100%) rename {frontend/public => public}/locales/it/translation.json (100%) rename {frontend/public => public}/locales/ja/translation.json (100%) rename {frontend/public => public}/locales/lt/translation.json (100%) rename {frontend/public => public}/locales/lv/translation.json (100%) rename {frontend/public => public}/locales/nl/translation.json (100%) rename {frontend/public => public}/locales/ru/translation.json (100%) rename {frontend/public => public}/locales/tr/translation.json (100%) rename {frontend/public => public}/locales/zh-CN/translation.json (100%) rename {frontend/public => public}/locales/zh-TW/translation.json (100%) rename {frontend/public => public}/tauri.svg (100%) rename {frontend/public => public}/vite.svg (100%) rename {frontend/public => public}/wallet-connect-screens/wallet-connect.html (100%) rename {frontend/public => public}/wallet-connect-screens/wallet-connect.js (100%) rename {frontend/public => public}/wc-images/balance.svg (100%) rename {frontend/public => public}/wc-images/connect.svg (100%) rename {frontend/public => public}/wc-images/decrypt.svg (100%) rename {frontend/public => public}/wc-images/deploy.svg (100%) rename {frontend/public => public}/wc-images/execute.svg (100%) rename {frontend/public => public}/wc-images/sign.svg (100%) rename {frontend/public => public}/wc-images/transactions.svg (100%) rename {frontend/public => public}/wc-images/tx.svg (100%) rename {frontend/src => src}/App.tsx (100%) rename {frontend/src => src}/assets/dapps/ans.svg (100%) rename {frontend/src => src}/assets/dapps/arcane.svg (100%) rename {frontend/src => src}/assets/dapps/dapps.ts (100%) rename {frontend/src => src}/assets/dapps/shadowfi.png (100%) rename {frontend/src => src}/assets/dapps/staking.png (100%) rename {frontend/src => src}/assets/fonts/DMsans/DMSans-Bold.ttf (100%) rename {frontend/src => src}/assets/fonts/DMsans/DMSans-ExtraBold.ttf (100%) rename {frontend/src => src}/assets/fonts/DMsans/DMSans-ExtraLight.ttf (100%) rename {frontend/src => src}/assets/fonts/DMsans/DMSans-Italic.ttf (100%) rename {frontend/src => src}/assets/fonts/DMsans/DMSans-Light.ttf (100%) rename {frontend/src => src}/assets/fonts/DMsans/DMSans-Medium.ttf (100%) rename {frontend/src => src}/assets/fonts/DMsans/DMSans-Regular.ttf (100%) rename {frontend/src => src}/assets/fonts/DMsans/DMSans-SemiBold.ttf (100%) rename {frontend/src => src}/assets/fonts/DMsans/DMSans-Thin.ttf (100%) rename {frontend/src => src}/assets/icons/contracts/house-loan.svg (100%) rename {frontend/src => src}/assets/icons/contracts/loan-icon.svg (100%) rename {frontend/src => src}/assets/icons/contracts/rent-icon.svg (100%) rename {frontend/src => src}/assets/icons/contracts/sale-icon.svg (100%) rename {frontend/src => src}/assets/icons/contracts/service-icon.svg (100%) rename {frontend/src => src}/assets/icons/contracts/web-dev-icon.svg (100%) rename {frontend/src => src}/assets/icons/hub-icon-green.svg (100%) rename {frontend/src => src}/assets/icons/hub-icon.svg (100%) rename {frontend/src => src}/assets/icons/notification.svg (100%) rename {frontend/src => src}/assets/icons/qr-code.svg (100%) rename {frontend/src => src}/assets/icons/tokens/aleo.svg (100%) rename {frontend/src => src}/assets/icons/tokens/usdt.svg (100%) rename {frontend/src => src}/assets/images/backgrounds/sign-up-bg.jpeg (100%) rename {frontend/src => src}/assets/images/backgrounds/sign-up-bg.svg (100%) rename {frontend/src => src}/assets/images/backup.svg (100%) rename {frontend/src => src}/assets/images/login-dalle.svg (100%) rename {frontend/src => src}/assets/images/tokens/ALEO.svg (100%) rename {frontend/src => src}/assets/images/tokens/USDC.svg (100%) rename {frontend/src => src}/assets/logo/a-icon.svg (100%) rename {frontend/src => src}/assets/logo/desktop-full-logo.svg (100%) rename {frontend/src => src}/assets/logo/full-logo.svg (100%) rename {frontend/src => src}/assets/notification-icons/nannouncement.svg (100%) rename {frontend/src => src}/assets/notification-icons/ncontract.svg (100%) rename {frontend/src => src}/assets/notification-icons/nheart.svg (100%) rename {frontend/src => src}/assets/notification-icons/nloan_accepted.svg (100%) rename {frontend/src => src}/assets/notification-icons/nloan_request.svg (100%) rename {frontend/src => src}/assets/notification-icons/npayment.svg (100%) rename {frontend/src => src}/assets/react.svg (100%) rename {frontend/src => src}/browser/nova_browser.tsx (100%) rename {frontend/src => src}/components/account/details.tsx (100%) rename {frontend/src => src}/components/account/profile-header.tsx (100%) rename {frontend/src => src}/components/assets/asset.tsx (100%) rename {frontend/src => src}/components/assets/asset_drawer.tsx (100%) rename {frontend/src => src}/components/assets/balances.tsx (100%) rename {frontend/src => src}/components/backup/backup_dialog.tsx (100%) rename {frontend/src => src}/components/balance.tsx (100%) rename {frontend/src => src}/components/buttons/back.tsx (100%) rename {frontend/src => src}/components/buttons/cta.tsx (100%) rename {frontend/src => src}/components/buttons/home_options.tsx (100%) rename {frontend/src => src}/components/buttons/login-button.tsx (100%) rename {frontend/src => src}/components/buttons/secure-button.tsx (100%) rename {frontend/src => src}/components/buttons/settings-button.tsx (100%) rename {frontend/src => src}/components/buttons/sign-up-button.tsx (100%) rename {frontend/src => src}/components/buttons/transfer_cta.tsx (100%) rename {frontend/src => src}/components/chat/add_contact.tsx (100%) rename {frontend/src => src}/components/chat/friend.tsx (100%) rename {frontend/src => src}/components/chat/message.tsx (100%) rename {frontend/src => src}/components/chat/message_bar.tsx (100%) rename {frontend/src => src}/components/chat/new_transfer.tsx (100%) rename {frontend/src => src}/components/chat/room.tsx (100%) rename {frontend/src => src}/components/contracts/contractItem.tsx (100%) rename {frontend/src => src}/components/contracts/contract_bottom_bar.tsx (100%) rename {frontend/src => src}/components/dApps/dapp.tsx (100%) rename {frontend/src => src}/components/dialogs/delete.tsx (100%) rename {frontend/src => src}/components/dialogs/disable_backup.tsx (100%) rename {frontend/src => src}/components/dialogs/keys/get_private_key.tsx (100%) rename {frontend/src => src}/components/dialogs/keys/get_seed_phrase.tsx (100%) rename {frontend/src => src}/components/dialogs/keys/get_viewing_key.tsx (100%) rename {frontend/src => src}/components/dialogs/logout.tsx (100%) rename {frontend/src => src}/components/dialogs/reauth.tsx (100%) rename {frontend/src => src}/components/dialogs/receive.tsx (100%) rename {frontend/src => src}/components/dialogs/scan_reauth.tsx (100%) rename {frontend/src => src}/components/dialogs/transfer.tsx (100%) rename {frontend/src => src}/components/dialogs/username.tsx (100%) rename {frontend/src => src}/components/events/event.tsx (100%) rename {frontend/src => src}/components/events/event_drawer.tsx (100%) rename {frontend/src => src}/components/events/explorer.tsx (100%) rename {frontend/src => src}/components/events/transition.tsx (100%) rename {frontend/src => src}/components/header/appbar.tsx (100%) rename {frontend/src => src}/components/header/chat_header.tsx (100%) rename {frontend/src => src}/components/header/contract_header.tsx (100%) rename {frontend/src => src}/components/header/header.tsx (100%) rename {frontend/src => src}/components/header/simple_appbar.tsx (100%) rename {frontend/src => src}/components/header/transfer_header.tsx (100%) rename {frontend/src => src}/components/icons/received.tsx (100%) rename {frontend/src => src}/components/icons/sent.tsx (100%) rename {frontend/src => src}/components/loadingScreen.tsx (100%) rename {frontend/src => src}/components/menu/options.tsx (100%) rename {frontend/src => src}/components/nft.tsx (100%) rename {frontend/src => src}/components/notifications/notification.tsx (100%) rename {frontend/src => src}/components/notifications/slider.tsx (100%) rename {frontend/src => src}/components/searchabar.tsx (100%) rename {frontend/src => src}/components/select/language.tsx (100%) rename {frontend/src => src}/components/select/seed_length.tsx (100%) rename {frontend/src => src}/components/settings/general.tsx (100%) rename {frontend/src => src}/components/sidebar.tsx (100%) rename {frontend/src => src}/components/snackbars/alerts.tsx (100%) rename {frontend/src => src}/components/switch/privacy_toggle.tsx (100%) rename {frontend/src => src}/components/textfields/white-hue.tsx (100%) rename {frontend/src => src}/components/transfer/token_dropdown.tsx (100%) rename {frontend/src => src}/components/transfer/transfer_box.tsx (100%) rename {frontend/src => src}/components/typography/typography.tsx (100%) rename {frontend/src => src}/context/EventsContext.tsx (100%) rename {frontend/src => src}/context/ScanContext.tsx (100%) rename {frontend/src => src}/context/WalletConnect.tsx (100%) rename {frontend/src => src}/i18next-config.ts (100%) rename {frontend/src => src}/index.css (100%) rename {frontend/src => src}/main.tsx (100%) rename {frontend/src => src}/services/authentication/auth.ts (100%) rename {frontend/src => src}/services/authentication/register.ts (100%) rename {frontend/src => src}/services/events/get_events.ts (100%) rename {frontend/src => src}/services/keychain/keychain.ts (100%) rename {frontend/src => src}/services/nfts/fetch.ts (100%) rename {frontend/src => src}/services/recovery/phrase.ts (100%) rename {frontend/src => src}/services/scans/backup.ts (100%) rename {frontend/src => src}/services/scans/blocks.ts (100%) rename {frontend/src => src}/services/scans/encrypted_messages.ts (100%) rename {frontend/src => src}/services/states/utils.ts (100%) rename {frontend/src => src}/services/storage/keys.ts (100%) rename {frontend/src => src}/services/storage/localStorage.ts (100%) rename {frontend/src => src}/services/storage/persistent.ts (100%) rename {frontend/src => src}/services/tokens/get_balance.ts (100%) rename {frontend/src => src}/services/tokens/get_tokens.ts (100%) rename {frontend/src => src}/services/transfer/inclusion.ts (100%) rename {frontend/src => src}/services/transfer/transfers.ts (100%) rename {frontend/src => src}/services/util/functions.ts (100%) rename {frontend/src => src}/services/util/open.ts (100%) rename {frontend/src => src}/services/util/sign.ts (100%) rename {frontend/src => src}/services/wallet-connect/AleoWallet.ts (100%) rename {frontend/src => src}/services/wallet-connect/SessionInfo.ts (100%) rename {frontend/src => src}/services/wallet-connect/WCTypes.ts (100%) rename {frontend/src => src}/services/wallet-connect/WalletConnectManager.ts (100%) rename {frontend/src => src}/styles/animations.css (100%) rename {frontend/src => src}/styles/shapes.css (100%) rename {frontend/src => src}/styles/theme.ts (100%) rename {frontend/src => src}/types/assets/asset.ts (100%) rename {frontend/src => src}/types/auth.ts (100%) rename {frontend/src => src}/types/avail-events/event.ts (100%) rename {frontend/src => src}/types/chat/messages.ts (100%) rename {frontend/src => src}/types/chat/room.ts (100%) rename {frontend/src => src}/types/contracts/service.ts (100%) rename {frontend/src => src}/types/errors.ts (100%) rename {frontend/src => src}/types/events.ts (100%) rename {frontend/src => src}/types/languages.ts (100%) rename {frontend/src => src}/types/nfts/nft.ts (100%) rename {frontend/src => src}/types/notification.tsx (100%) rename {frontend/src => src}/types/transfer_props/tokens.ts (100%) rename {frontend/src => src}/types/user_preferences.ts (100%) rename {frontend/src => src}/views-desktop/activity.tsx (100%) rename {frontend/src => src}/views-desktop/browser.tsx (100%) rename {frontend/src => src}/views-desktop/entrypoint.tsx (100%) rename {frontend/src => src}/views-desktop/home-desktop.tsx (100%) rename {frontend/src => src}/views-desktop/login.tsx (100%) rename {frontend/src => src}/views-desktop/nft.tsx (100%) rename {frontend/src => src}/views-desktop/oops.tsx (100%) rename {frontend/src => src}/views-desktop/privacy-policy.tsx (100%) rename {frontend/src => src}/views-desktop/recovery.tsx (100%) rename {frontend/src => src}/views-desktop/register.tsx (100%) rename {frontend/src => src}/views-desktop/reusable/bottom-nav.tsx (100%) rename {frontend/src => src}/views-desktop/reusable/layout.tsx (100%) rename {frontend/src => src}/views-desktop/seedphrase.tsx (100%) rename {frontend/src => src}/views-desktop/send.tsx (100%) rename {frontend/src => src}/views-desktop/settings.tsx (100%) rename {frontend/src => src}/views-desktop/terms-and-conditions.tsx (100%) rename {frontend/src => src}/views-desktop/verify.tsx (100%) rename {frontend/src => src}/vite-env.d.ts (100%) rename frontend/tsconfig.json => tsconfig.json (100%) rename frontend/tsconfig.node.json => tsconfig.node.json (100%) rename frontend/vite.config.ts => vite.config.ts (100%) diff --git a/.github/workflows/tauri.yml b/.github/workflows/release.yml similarity index 89% rename from .github/workflows/tauri.yml rename to .github/workflows/release.yml index 6be0c1b7..6ab8a9f6 100644 --- a/.github/workflows/tauri.yml +++ b/.github/workflows/release.yml @@ -78,13 +78,14 @@ jobs: - name: Initialize Rust cache uses: swatinem/rust-cache@v2 with: - workspaces: './backend -> target' + workspaces: './src-tauri -> target' - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' + - run: npm install - name: Install dependencies (ubuntu only) if: matrix.platform == 'ubuntu-latest' @@ -92,11 +93,6 @@ jobs: sudo apt-get update sudo apt-get install -y libsoup-3.0-dev libwebkit2gtk-4.1-dev patchelf javascriptcoregtk-4.1 build-essential curl wget file libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev - - name: Install Tauri CLI - run: | - npm i @tauri-apps/cli@2.0.0-beta.1 - - # If tagName and releaseId are omitted tauri-action will only build the app and won't try to upload any asstes. - uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -114,12 +110,8 @@ jobs: MAINNET_API_OBSCURA: "" DEVNET_API_OBSCURA: "" with: - # Use the tauri-cli we installed earlier - tauriScript: cargo tauri - # Build for the ARM architecture on macOS - args: ${{ matrix.platform == 'macos_arm-latest' && ' --target aarch64-apple-darwin' || '' }} - projectPath: backend - distPath: frontend/dist + args: ${{ matrix.platform == 'macos_arm-latest' && ' --target aarch64-apple-darwin' || '' }} # This is required for Apple ARM chips + distPath: dist # The tagName is alpha for develop, beta for staging and latest for release includeDebug: ${{ github.ref_name == 'release' && false || true }} includeRelease: ${{ github.ref_name == 'release' && true || false }} diff --git a/.github/workflows/rust-clippy.yml b/.github/workflows/rust-clippy.yml index e81551e4..3ebd14aa 100644 --- a/.github/workflows/rust-clippy.yml +++ b/.github/workflows/rust-clippy.yml @@ -42,6 +42,7 @@ jobs: run: cargo clippy --all-features + --manifest-path=src-tauri/Cargo.toml --message-format=json | clippy-sarif | tee rust-clippy-results.sarif | sarif-fmt continue-on-error: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 424dec9d..319bb162 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,6 +51,7 @@ jobs: with: node-version: 20 cache: 'npm' + - run: npm install - name: Install dependencies (ubuntu only) if: matrix.platform == 'ubuntu-latest' @@ -58,10 +59,6 @@ jobs: sudo apt-get update sudo apt-get install -y libsoup-3.0-dev libwebkit2gtk-4.1-dev patchelf javascriptcoregtk-4.1 build-essential curl wget file libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev - - name: Install Tauri CLI - run: | - npm i @tauri-apps/cli@2.0.0-beta.1 - - uses: tauri-apps/tauri-action@v0 env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY}} @@ -72,8 +69,4 @@ jobs: MAINNET_API_OBSCURA: "" DEVNET_API_OBSCURA: "" with: - # Use the tauri-cli we installed earlier - tauriScript: npm tauri - # Build for the ARM architecture on macOS - projectPath: backend - distPath: frontend/dist + distPath: dist diff --git a/.gitignore b/.gitignore index bc6f46a4..762f008b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,34 @@ **/target/ **/node_modules **/.DS_Store + +node_modules/** +dist/** +build/** +.cargo/config.toml + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.vscode/* diff --git a/backend/.gitignore b/backend/.gitignore deleted file mode 100644 index 91eab81d..00000000 --- a/backend/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -gen/** -target/** -.cargo/** -.env diff --git a/backend/Cargo.lock b/backend/Cargo.lock deleted file mode 100644 index b6f47209..00000000 --- a/backend/Cargo.lock +++ /dev/null @@ -1,7561 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher 0.3.0", - "cpufeatures", - "opaque-debug", -] - -[[package]] -name = "aes" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" -dependencies = [ - "cfg-if", - "cipher 0.4.4", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes 0.8.3", - "cipher 0.4.4", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" -dependencies = [ - "memchr", -] - -[[package]] -name = "aleo-std" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3aa6ad1a3bb96698e7e8d8e42a6f2fda3b8611a43aab4d5effb921f18798833" -dependencies = [ - "aleo-std-cpu", - "aleo-std-profiler", - "aleo-std-storage", - "aleo-std-time", - "aleo-std-timed", - "aleo-std-timer", -] - -[[package]] -name = "aleo-std-cpu" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7527351aa675fdbe6a1902de3cf913ff7d50ccd6822f1562be374bdd85eaefb8" - -[[package]] -name = "aleo-std-profiler" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf055ddb2f54fa86394d19d87e7956df2f3cafff489fc14c0f48f2f80664c3d" - -[[package]] -name = "aleo-std-storage" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503e2538d5158b869bc9c30c9754f9a23f4210987008014a9f118db99f22c217" -dependencies = [ - "dirs 4.0.0", -] - -[[package]] -name = "aleo-std-time" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f2a841f04c2eaeb5a95312e5201a9e4b7c95b64ca99870d6bd2e2376df540a" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "aleo-std-timed" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6118baab6285accf088b31d5ea5029c37bbf9d98e62b4d8720a0a5a66bc2e427" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "aleo-std-timer" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4f181fc1a372e8ceff89612e5c9b13f72bff5b066da9f8d6827ae65af492c4" - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "allocator-api2" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" - -[[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 = "anstream" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" - -[[package]] -name = "anstyle-parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "anstyle-wincon" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" -dependencies = [ - "anstyle", - "windows-sys 0.48.0", -] - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "app_dirs2" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7e7b35733e3a8c1ccb90385088dd5b6eaa61325cb4d1ad56e683b5224ff352e" -dependencies = [ - "jni", - "ndk-context", - "winapi 0.3.9", - "xdg", -] - -[[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "as-raw-xcb-connection" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" - -[[package]] -name = "async-broadcast" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" -dependencies = [ - "event-listener", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-executor" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" -dependencies = [ - "async-lock", - "async-task", - "concurrent-queue", - "fastrand 1.9.0", - "futures-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" -dependencies = [ - "async-lock", - "autocfg", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite", - "log", - "parking", - "polling", - "rustix 0.37.24", - "slab", - "socket2 0.4.9", - "waker-fn", -] - -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-process" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" -dependencies = [ - "async-io", - "async-lock", - "autocfg", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix 0.37.24", - "signal-hook", - "windows-sys 0.48.0", -] - -[[package]] -name = "async-recursion" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "async-task" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" - -[[package]] -name = "async-trait" -version = "0.1.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2d0f03b3640e3a630367e40c468cb7f309529c708ed1d88597047b0e7c6ef7" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "atk" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4af014b17dd80e8af9fa689b2d4a211ddba6eb583c1622f35d0cb543f6b17e4" -dependencies = [ - "atk-sys", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "atomic-waker" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "avail-common" -version = "0.5.0" -source = "git+https://github.com/availx/avail-lib?tag=v0.5.0#9db153348a031d5a94c674fa1187182b5d65ca4e" -dependencies = [ - "aes-gcm", - "app_dirs2", - "bincode", - "bs58", - "chrono", - "duration-str", - "hex", - "jni", - "keyring", - "once_cell", - "rand 0.8.5", - "reqwest", - "rusqlite", - "rust-argon2", - "security-framework 2.9.1", - "security-framework-sys 2.9.0", - "serde", - "serde_json", - "snarkvm", - "tokio", - "tracing", - "ureq", - "url", - "uuid", -] - -[[package]] -name = "avail_wallet" -version = "0.0.1" -dependencies = [ - "app_dirs2", - "avail-common", - "bs58", - "chrono", - "core-foundation", - "dirs 5.0.1", - "dotenv", - "fix-path-env", - "futures", - "jni", - "keyring", - "libc", - "log", - "ndk-context", - "once_cell", - "openssl", - "rand 0.8.5", - "rayon", - "rstest", - "rusqlite", - "security-framework 2.9.1", - "security-framework-sys 2.9.0", - "serde", - "serde_json", - "snarkvm", - "ssss", - "tauri", - "tauri-build", - "tauri-plugin-deep-link", - "tauri-plugin-http", - "tauri-plugin-updater", - "tid-rs", - "tiny-bip39", - "tokio", - "ureq", - "uuid", - "whoami", - "zeroize", -] - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" -dependencies = [ - "serde", -] - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - -[[package]] -name = "blake2b_simd" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq 0.3.0", -] - -[[package]] -name = "blake2s_simd" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq 0.3.0", -] - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[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 = "block-modes" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" -dependencies = [ - "block-padding", - "cipher 0.3.0", -] - -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - -[[package]] -name = "blocking" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" -dependencies = [ - "async-channel", - "async-lock", - "async-task", - "atomic-waker", - "fastrand 1.9.0", - "futures-lite", - "log", -] - -[[package]] -name = "brotli" -version = "3.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bs58" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "bumpalo" -version = "3.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" - -[[package]] -name = "bytemuck" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" -dependencies = [ - "serde", -] - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "cairo-rs" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" -dependencies = [ - "bitflags 2.4.0", - "cairo-sys-rs", - "glib", - "libc", - "once_cell", - "thiserror", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "camino" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "cargo_toml" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a969e13a7589e9e3e4207e153bae624ade2b5622fb4684a4923b23ec3d57719" -dependencies = [ - "serde", - "toml 0.8.2", -] - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" -dependencies = [ - "jobserver", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cfb" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" -dependencies = [ - "byteorder", - "fnv", - "uuid", -] - -[[package]] -name = "cfg-expr" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" -dependencies = [ - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - -[[package]] -name = "cfg_aliases" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e53693616d3075149f4ead59bdeecd204ac6b8192d8969757601b74bddf00f" - -[[package]] -name = "chrono" -version = "0.4.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-targets 0.48.5", -] - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "clap" -version = "4.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824956d0dca8334758a5b7f7e50518d66ea319330cbceedcf76905c2f6ab30e3" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122ec64120a49b4563ccaedcbea7818d069ed8e9aa6d829b82d8a4128936b2ab" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" -dependencies = [ - "heck", - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "clap_lex" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" - -[[package]] -name = "cocoa" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" -dependencies = [ - "bitflags 1.3.2", - "block", - "cocoa-foundation", - "core-foundation", - "core-graphics", - "foreign-types 0.5.0", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" -dependencies = [ - "bitflags 1.3.2", - "block", - "core-foundation", - "core-graphics-types", - "libc", - "objc", -] - -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "colored" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" -dependencies = [ - "is-terminal", - "lazy_static", - "windows-sys 0.48.0", -] - -[[package]] -name = "combine" -version = "4.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "concurrent-queue" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "console" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "unicode-width", - "windows-sys 0.45.0", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "constant_time_eq" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cookie" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - -[[package]] -name = "cookie_store" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa" -dependencies = [ - "cookie", - "idna 0.2.3", - "log", - "publicsuffix", - "serde", - "serde_derive", - "serde_json", - "time", - "url", -] - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "core-graphics" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-graphics-types", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset 0.9.0", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "typenum", -] - -[[package]] -name = "cssparser" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa 0.4.8", - "matches", - "phf 0.8.0", - "proc-macro2", - "quote 1.0.35", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "ctor" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" -dependencies = [ - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher 0.4.4", -] - -[[package]] -name = "curl" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2 0.4.9", - "winapi 0.3.9", -] - -[[package]] -name = "curl-sys" -version = "0.4.66+curl-8.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70c44a72e830f0e40ad90dda8a6ab6ed6314d39776599a58a2e5e37fbc6db5b9" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys 0.48.0", -] - -[[package]] -name = "darling" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote 1.0.35", - "strsim", - "syn 2.0.49", -] - -[[package]] -name = "darling_macro" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" -dependencies = [ - "darling_core", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "data-url" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote 1.0.35", - "rustc_version", - "syn 1.0.109", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys 0.3.7", -] - -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys 0.4.1", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi 0.3.9", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi 0.3.9", -] - -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading 0.7.4", -] - -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]] -name = "downcast-rs" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" - -[[package]] -name = "drm" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde" -dependencies = [ - "bitflags 2.4.0", - "bytemuck", - "drm-ffi", - "drm-fourcc", - "rustix 0.38.31", -] - -[[package]] -name = "drm-ffi" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41334f8405792483e32ad05fbb9c5680ff4e84491883d2947a4757dc54cb2ac6" -dependencies = [ - "drm-sys", - "rustix 0.38.31", -] - -[[package]] -name = "drm-fourcc" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" - -[[package]] -name = "drm-sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d09ff881f92f118b11105ba5e34ff8f4adf27b30dae8f12e28c193af1c83176" -dependencies = [ - "libc", - "linux-raw-sys 0.6.4", -] - -[[package]] -name = "dtoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65d09067bfacaa79114679b279d7f5885b53295b1e2cfb4e79c8e4bd3d633169" - -[[package]] -name = "dtoa-short" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" -dependencies = [ - "dtoa", -] - -[[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - -[[package]] -name = "duration-str" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e172e85f305d6a442b250bf40667ffcb91a24f52c9a1ca59e2fa991ac9b7790" -dependencies = [ - "chrono", - "nom", - "rust_decimal", - "serde", - "thiserror", - "time", -] - -[[package]] -name = "dyn-clone" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "embed-resource" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80663502655af01a2902dff3f06869330782267924bf1788410b74edcd93770a" -dependencies = [ - "cc", - "rustc_version", - "toml 0.7.4", - "vswhom", - "winreg 0.11.0", -] - -[[package]] -name = "embed_plist" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enum_index" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5532bdea562e7be83060c36185eecccba82fe16729d2eaad2891d65417656dd" - -[[package]] -name = "enum_index_derive" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ab22c8085548bf06190113dca556e149ecdbb05ae5b972a2b9899f26b944ee4" -dependencies = [ - "quote 0.3.15", - "syn 0.11.11", -] - -[[package]] -name = "enumflags2" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5998b4f30320c9d93aed72f63af821bfdac50465b75428fce77b48ec482c3939" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "fdeflate" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "field-offset" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" -dependencies = [ - "memoffset 0.9.0", - "rustc_version", -] - -[[package]] -name = "filetime" -version = "0.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", -] - -[[package]] -name = "fix-path-env" -version = "0.0.0" -source = "git+https://github.com/tauri-apps/fix-path-env-rs#8481725b7ebfc56cdb052d522517421242eac36b" -dependencies = [ - "strip-ansi-escapes", - "thiserror", -] - -[[package]] -name = "flate2" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared 0.3.1", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-timer" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gdk" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ba081bdef3b75ebcdbfc953699ed2d7417d6bd853347a42a37d76406a33646" -dependencies = [ - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" -dependencies = [ - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", - "once_cell", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gdk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkwayland-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90fbf5c033c65d93792192a49a8efb5bb1e640c419682a58bb96f5ae77f3d4a" -dependencies = [ - "gdk-sys", - "glib-sys", - "gobject-sys", - "libc", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkx11" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2ea8a4909d530f79921290389cbd7c34cb9d623bfe970eaae65ca5f9cd9cce" -dependencies = [ - "gdk", - "gdkx11-sys", - "gio", - "glib", - "libc", - "x11", -] - -[[package]] -name = "gdkx11-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee8f00f4ee46cad2939b8990f5c70c94ff882c3028f3cc5abf950fa4ab53043" -dependencies = [ - "gdk-sys", - "glib-sys", - "libc", - "system-deps", - "x11", -] - -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows 0.48.0", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "gethostname" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" -dependencies = [ - "libc", - "windows-targets 0.48.5", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getset" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "ghash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" - -[[package]] -name = "gio" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "once_cell", - "pin-project-lite", - "smallvec", - "thiserror", -] - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi 0.3.9", -] - -[[package]] -name = "glib" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" -dependencies = [ - "bitflags 2.4.0", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror", -] - -[[package]] -name = "glib-macros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" -dependencies = [ - "heck", - "proc-macro-crate 2.0.1", - "proc-macro-error", - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "gobject-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gtk" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c4f5e0e20b60e10631a5f06da7fe3dda744b05ad0ea71fee2f47adf865890c" -dependencies = [ - "atk", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps", -] - -[[package]] -name = "gtk3-macros" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6063efb63db582968fb7df72e1ae68aa6360dcfb0a75143f34fc7d616bad75e" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "h2" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 1.9.3", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" -dependencies = [ - "ahash", - "allocator-api2", -] - -[[package]] -name = "hashlink" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" -dependencies = [ - "hashbrown 0.14.0", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hkdf" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever", - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa 1.0.6", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa 1.0.6", - "pin-project-lite", - "socket2 0.4.9", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows 0.48.0", -] - -[[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 = "ico" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae" -dependencies = [ - "byteorder", - "png", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "image" -version = "0.24.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "num-rational", - "num-traits", -] - -[[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.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" -dependencies = [ - "equivalent", - "hashbrown 0.14.0", - "rayon", - "serde", -] - -[[package]] -name = "indicatif" -version = "0.17.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" -dependencies = [ - "console", - "instant", - "number_prefix", - "portable-atomic", - "unicode-width", -] - -[[package]] -name = "infer" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199" -dependencies = [ - "cfb", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "ipnet" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" - -[[package]] -name = "is-terminal" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" -dependencies = [ - "hermit-abi", - "rustix 0.38.31", - "windows-sys 0.48.0", -] - -[[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 = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "javascriptcore-rs" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" -dependencies = [ - "bitflags 1.3.2", - "glib", - "javascriptcore-rs-sys", -] - -[[package]] -name = "javascriptcore-rs-sys" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir 2.3.3", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "json-patch" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ff1e1486799e3f64129f8ccad108b38290df9cd7015cd31bed17239f0789d6" -dependencies = [ - "serde", - "serde_json", - "thiserror", - "treediff", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[package]] -name = "keyboard-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" -dependencies = [ - "bitflags 2.4.0", - "serde", - "unicode-segmentation", -] - -[[package]] -name = "keyring" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9549a129bd08149e0a71b2d1ce2729780d47127991bfd0a78cc1df697ec72492" -dependencies = [ - "byteorder", - "lazy_static", - "linux-keyutils", - "secret-service", - "security-framework 2.9.2", - "winapi 0.3.9", -] - -[[package]] -name = "kuchikiki" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" -dependencies = [ - "cssparser", - "html5ever", - "indexmap 1.9.3", - "matches", - "selectors", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libappindicator" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" -dependencies = [ - "glib", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" -dependencies = [ - "gtk-sys", - "libloading 0.7.4", - "once_cell", -] - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi 0.3.9", -] - -[[package]] -name = "libloading" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "libz-sys" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "line-wrap" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" -dependencies = [ - "safemem", -] - -[[package]] -name = "linux-keyutils" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f27bb67f6dd1d0bb5ab582868e4f65052e58da6401188a08f0da09cf512b84b" -dependencies = [ - "bitflags 1.3.2", - "libc", -] - -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "linux-raw-sys" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b5399f6804fbab912acbd8878ed3532d506b7c951b8f9f164ef90fef39e3f4" - -[[package]] -name = "lock_api" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - -[[package]] -name = "markup5ever" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" -dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen 0.10.0", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memmap2" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" -dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "minisign-verify" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "933dca44d65cdd53b355d0b73d380a2ff5da71f87f036053188bf1eab6a19881" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - -[[package]] -name = "muda" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e406691fa7749604bbc7964bde28a300572d52621bb84540f6907c0f8fe08737" -dependencies = [ - "cocoa", - "crossbeam-channel", - "gtk", - "keyboard-types", - "objc", - "once_cell", - "png", - "serde", - "thiserror", - "windows-sys 0.52.0", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework 2.9.2", - "security-framework-sys 2.9.1", - "tempfile", -] - -[[package]] -name = "ndk" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" -dependencies = [ - "bitflags 1.3.2", - "jni-sys", - "ndk-sys", - "num_enum", - "raw-window-handle 0.5.2", - "thiserror", -] - -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.4.1+23.1.7779620" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" -dependencies = [ - "jni-sys", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nix" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", - "memoffset 0.7.1", -] - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi 0.3.9", -] - -[[package]] -name = "num" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "num-derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "num-format" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" -dependencies = [ - "arrayvec", - "itoa 1.0.6", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "number_prefix" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", - "objc_exception", -] - -[[package]] -name = "objc_exception" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" -dependencies = [ - "cc", -] - -[[package]] -name = "objc_id" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" -dependencies = [ - "objc", -] - -[[package]] -name = "object" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" -dependencies = [ - "bitflags 2.4.0", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.1.5+3.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559068e4c12950d7dcaa1857a61725c0d38d4fc03ff8e070ab31a75d6e316491" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "ordered-stream" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" -dependencies = [ - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "pango" -version = "0.18.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" -dependencies = [ - "gio", - "glib", - "libc", - "once_cell", - "pango-sys", -] - -[[package]] -name = "pango-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "parking" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.3.5", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_macros 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "plist" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdc0001cfea3db57a2e24bc0d818e9e20e554b5f97fabb9bc231dc240269ae06" -dependencies = [ - "base64", - "indexmap 1.9.3", - "line-wrap", - "quick-xml 0.29.0", - "serde", - "time", -] - -[[package]] -name = "png" -version = "0.17.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "polyval" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "portable-atomic" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.10", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" -dependencies = [ - "toml_datetime", - "toml_edit 0.20.2", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "version_check", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "psl-types" -version = "2.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" - -[[package]] -name = "publicsuffix" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" -dependencies = [ - "idna 0.3.0", - "psl-types", -] - -[[package]] -name = "quick-xml" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bafc859c6815fbaffbbbf4229ecb767ac913fecb27f9ad4343662e9ef099ea" -dependencies = [ - "memchr", -] - -[[package]] -name = "quick-xml" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" -dependencies = [ - "memchr", -] - -[[package]] -name = "quick-xml" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" -dependencies = [ - "memchr", -] - -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[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 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.10", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core 0.6.4", -] - -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - -[[package]] -name = "raw-window-handle" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" - -[[package]] -name = "rayon" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom 0.2.10", - "redox_syscall 0.2.16", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.3.7", - "regex-syntax 0.7.5", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.7.5", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "relative-path" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" - -[[package]] -name = "reqwest" -version = "0.11.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" -dependencies = [ - "base64", - "bytes", - "cookie", - "cookie_store", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "winreg 0.50.0", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi 0.3.9", -] - -[[package]] -name = "rstest" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97eeab2f3c0a199bc4be135c36c924b6590b88c377d416494288c14f2db30199" -dependencies = [ - "futures", - "futures-timer", - "rstest_macros", - "rustc_version", -] - -[[package]] -name = "rstest_macros" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" -dependencies = [ - "cfg-if", - "glob", - "proc-macro2", - "quote 1.0.35", - "regex", - "relative-path", - "rustc_version", - "syn 2.0.49", - "unicode-ident", -] - -[[package]] -name = "rusqlite" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" -dependencies = [ - "bitflags 2.4.0", - "chrono", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", -] - -[[package]] -name = "rust-argon2" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5885493fdf0be6cdff808d1533ce878d21cfa49c7086fa00c66355cd9141bfc" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq 0.3.0", - "crossbeam-utils", -] - -[[package]] -name = "rust_decimal" -version = "1.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c4216490d5a413bc6d10fa4742bd7d4955941d062c0ef873141d6b0e7b30fd" -dependencies = [ - "arrayvec", - "num-traits", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.37.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4279d76516df406a8bd37e7dff53fd37d1a093f997a3c34a5c21658c126db06d" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" -dependencies = [ - "bitflags 2.4.0", - "errno", - "libc", - "linux-raw-sys 0.4.13", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.6", - "sct", -] - -[[package]] -name = "rustls-webpki" -version = "0.100.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - -[[package]] -name = "same-file" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" -dependencies = [ - "kernel32-sys", - "winapi 0.2.8", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "schemars" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" -dependencies = [ - "dyn-clone", - "indexmap 1.9.3", - "schemars_derive", - "serde", - "serde_json", - "url", -] - -[[package]] -name = "schemars_derive" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "serde_derive_internals", - "syn 1.0.109", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "secret-service" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da1a5ad4d28c03536f82f77d9f36603f5e37d8869ac98f0a750d5b5686d8d95" -dependencies = [ - "aes 0.7.5", - "block-modes", - "futures-util", - "generic-array", - "hkdf", - "num", - "once_cell", - "rand 0.8.5", - "serde", - "sha2", - "zbus", -] - -[[package]] -name = "security-framework" -version = "2.9.1" -source = "git+https://github.com/AvailX/rust-security-framework#6bf8af0f251eb9a8181dee97ecb41a1bc45145b7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys 2.9.0", -] - -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys 2.9.1", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.0" -source = "git+https://github.com/AvailX/rust-security-framework#6bf8af0f251eb9a8181dee97ecb41a1bc45145b7" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "selectors" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "matches", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", - "thin-slice", -] - -[[package]] -name = "self-replace" -version = "1.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525db198616b2bcd0f245daf7bfd8130222f7ee6af9ff9984c19a61bf1160c55" -dependencies = [ - "fastrand 1.9.0", - "tempfile", - "windows-sys 0.48.0", -] - -[[package]] -name = "self_update" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b3c585a1ced6b97ac13bd5e56f66559e5a75f477da5913f70df98e114518446" -dependencies = [ - "hyper", - "indicatif", - "log", - "quick-xml 0.23.1", - "regex", - "reqwest", - "self-replace", - "semver", - "serde_json", - "tempfile", - "urlencoding", -] - -[[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.196" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.196" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "serde_derive_internals" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "serde_json" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" -dependencies = [ - "indexmap 2.0.0", - "itoa 1.0.6", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0a21fba416426ac927b1691996e82079f8b6156e920c85345f135b2e9ba2de" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "serde_spanned" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa 1.0.6", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513" -dependencies = [ - "base64", - "chrono", - "hex", - "indexmap 1.9.3", - "serde", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070" -dependencies = [ - "darling", - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "serialize-to-javascript" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" -dependencies = [ - "serde", - "serde_json", - "serialize-to-javascript-impl", -] - -[[package]] -name = "serialize-to-javascript-impl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "servo_arc" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" - -[[package]] -name = "smol_str" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" -dependencies = [ - "serde", -] - -[[package]] -name = "snarkvm" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c5327b3b6f3f6f90f267287480585fdefe430343567d928b7faf410e86c8a4" -dependencies = [ - "anstyle", - "anyhow", - "clap", - "colored", - "dotenvy", - "indexmap 2.0.0", - "num-format", - "once_cell", - "parking_lot", - "rand 0.8.5", - "rayon", - "self_update", - "serde_json", - "snarkvm-circuit", - "snarkvm-console", - "snarkvm-ledger", - "snarkvm-parameters", - "snarkvm-synthesizer", - "snarkvm-utilities", - "thiserror", - "ureq", - "walkdir 2.3.3", -] - -[[package]] -name = "snarkvm-algorithms" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26669ac56886463e8487bce6d14d72910218b33270fac9cc6fe43bbe350cc13c" -dependencies = [ - "aleo-std", - "anyhow", - "blake2", - "cfg-if", - "fxhash", - "hashbrown 0.14.0", - "hex", - "indexmap 2.0.0", - "itertools", - "num-traits", - "parking_lot", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "rayon", - "serde", - "sha2", - "smallvec", - "snarkvm-curves", - "snarkvm-fields", - "snarkvm-parameters", - "snarkvm-utilities", - "thiserror", -] - -[[package]] -name = "snarkvm-circuit" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b489ec6a10b47a601f6bbdfbe09e50aa02f108993764304c61b19b1cd5dd86ae" -dependencies = [ - "snarkvm-circuit-account", - "snarkvm-circuit-algorithms", - "snarkvm-circuit-collections", - "snarkvm-circuit-environment", - "snarkvm-circuit-network", - "snarkvm-circuit-program", - "snarkvm-circuit-types", -] - -[[package]] -name = "snarkvm-circuit-account" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04de0f281e8cb174db02a5aa6c8a799368e223c65b4dfa98d608832ca37c24cb" -dependencies = [ - "snarkvm-circuit-algorithms", - "snarkvm-circuit-network", - "snarkvm-circuit-types", - "snarkvm-console-account", -] - -[[package]] -name = "snarkvm-circuit-algorithms" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e48e2584ed51528640a1d2290baf12b1df48a1dae6fdda23b7654d7fdc7c5d4" -dependencies = [ - "snarkvm-circuit-types", - "snarkvm-console-algorithms", - "snarkvm-fields", -] - -[[package]] -name = "snarkvm-circuit-collections" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84f47b49192d8db8468ebe311e05e8db60f7c265f7fef39e50e419487b2825a" -dependencies = [ - "snarkvm-circuit-algorithms", - "snarkvm-circuit-types", - "snarkvm-console-collections", -] - -[[package]] -name = "snarkvm-circuit-environment" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff28494552a816376c48403f3072fea6707040a6a285ab3de1000220a31b2354" -dependencies = [ - "indexmap 2.0.0", - "itertools", - "nom", - "num-traits", - "once_cell", - "snarkvm-algorithms", - "snarkvm-circuit-environment-witness", - "snarkvm-console-network", - "snarkvm-curves", - "snarkvm-fields", - "snarkvm-utilities", -] - -[[package]] -name = "snarkvm-circuit-environment-witness" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76645b2e4b9d0e43d1cb6058daf7345b07de9345cd04da6ef04efdf40b44ae47" - -[[package]] -name = "snarkvm-circuit-network" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df782e802eecf25c299b4cd597d06e53597071640a5493c89e4d6aed91f66d2" -dependencies = [ - "snarkvm-circuit-algorithms", - "snarkvm-circuit-collections", - "snarkvm-circuit-types", - "snarkvm-console-network", -] - -[[package]] -name = "snarkvm-circuit-program" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e71f5ad7de2ca4d4b8e14105ca64fae07f4bcff4594b2e3f7bfbb4589ca3bc8e" -dependencies = [ - "paste", - "snarkvm-circuit-account", - "snarkvm-circuit-algorithms", - "snarkvm-circuit-collections", - "snarkvm-circuit-network", - "snarkvm-circuit-types", - "snarkvm-console-program", - "snarkvm-utilities", -] - -[[package]] -name = "snarkvm-circuit-types" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75c4a378bf31550b077385594761a22d22249a661bedd0aa228fbf695c457d86" -dependencies = [ - "snarkvm-circuit-environment", - "snarkvm-circuit-types-address", - "snarkvm-circuit-types-boolean", - "snarkvm-circuit-types-field", - "snarkvm-circuit-types-group", - "snarkvm-circuit-types-integers", - "snarkvm-circuit-types-scalar", - "snarkvm-circuit-types-string", -] - -[[package]] -name = "snarkvm-circuit-types-address" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf8ad07c0f70c9893389c9e6d1a24d152dd051e65c77f57d6ffeb59ce47a1cd" -dependencies = [ - "snarkvm-circuit-environment", - "snarkvm-circuit-types-boolean", - "snarkvm-circuit-types-field", - "snarkvm-circuit-types-group", - "snarkvm-circuit-types-scalar", - "snarkvm-console-types-address", -] - -[[package]] -name = "snarkvm-circuit-types-boolean" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9d81a0d28d89c599cf6b9a951bd1a365ba5bca7bab7c7c95ba9e5881ee3244" -dependencies = [ - "snarkvm-circuit-environment", - "snarkvm-console-types-boolean", -] - -[[package]] -name = "snarkvm-circuit-types-field" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c77c1d6412abe2bc5e1c8b6e6f3461d2d19a041836ea24bdcd3e24c308b72a1" -dependencies = [ - "snarkvm-circuit-environment", - "snarkvm-circuit-types-boolean", - "snarkvm-console-types-field", -] - -[[package]] -name = "snarkvm-circuit-types-group" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "191d7a14dad5fcb548ca367c43cdbd0560218c3dfb709a8fab934b50f8054829" -dependencies = [ - "snarkvm-circuit-environment", - "snarkvm-circuit-types-boolean", - "snarkvm-circuit-types-field", - "snarkvm-circuit-types-scalar", - "snarkvm-console-types-group", -] - -[[package]] -name = "snarkvm-circuit-types-integers" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5770d31bfa0c0732a1f03e786ac8adf12045e8200d47a496a6f79e2da97207b1" -dependencies = [ - "snarkvm-circuit-environment", - "snarkvm-circuit-types-boolean", - "snarkvm-circuit-types-field", - "snarkvm-circuit-types-scalar", - "snarkvm-console-types-integers", -] - -[[package]] -name = "snarkvm-circuit-types-scalar" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "019520127c534b60e7660e8d95881e8a075328e9ef0b6dfa5765e81ef72ef021" -dependencies = [ - "snarkvm-circuit-environment", - "snarkvm-circuit-types-boolean", - "snarkvm-circuit-types-field", - "snarkvm-console-types-scalar", -] - -[[package]] -name = "snarkvm-circuit-types-string" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd3632f0c72f767f3fa8d9d7ae954f70a249e33ac1ee377fdf294aec042c1f5" -dependencies = [ - "snarkvm-circuit-environment", - "snarkvm-circuit-types-boolean", - "snarkvm-circuit-types-field", - "snarkvm-circuit-types-integers", - "snarkvm-console-types-string", -] - -[[package]] -name = "snarkvm-console" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1589ee1c45788e798a27e5c6c9e77c407fc2fb23b8844430c8328c4530acf774" -dependencies = [ - "snarkvm-console-account", - "snarkvm-console-algorithms", - "snarkvm-console-collections", - "snarkvm-console-network", - "snarkvm-console-program", - "snarkvm-console-types", -] - -[[package]] -name = "snarkvm-console-account" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c63fffc49eb78d0187d4dab2cbc41ba816361a6682ffbfcc334d36463c767148" -dependencies = [ - "bs58", - "snarkvm-console-network", - "snarkvm-console-types", - "zeroize", -] - -[[package]] -name = "snarkvm-console-algorithms" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78de991dce272f0236573b8a759da19527f136d6f45031b2d059f67ef9ac1b02" -dependencies = [ - "blake2s_simd", - "smallvec", - "snarkvm-console-types", - "snarkvm-fields", - "snarkvm-utilities", - "tiny-keccak", -] - -[[package]] -name = "snarkvm-console-collections" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "344433096a532bb3787c5723c4db96a618f04186e8197cc2dc08437ef1f881b3" -dependencies = [ - "aleo-std", - "rayon", - "snarkvm-console-algorithms", - "snarkvm-console-types", -] - -[[package]] -name = "snarkvm-console-network" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36771f6bed6abf36eae21f0371d46a0e6c97608b118ee63339edf24ee7faaa53" -dependencies = [ - "anyhow", - "indexmap 2.0.0", - "itertools", - "lazy_static", - "once_cell", - "paste", - "serde", - "snarkvm-algorithms", - "snarkvm-console-algorithms", - "snarkvm-console-collections", - "snarkvm-console-network-environment", - "snarkvm-console-types", - "snarkvm-curves", - "snarkvm-fields", - "snarkvm-parameters", - "snarkvm-utilities", -] - -[[package]] -name = "snarkvm-console-network-environment" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd5ab64dc360d0148579b14a29de6e51c9fa456e7fac51ce944e254df549cad5" -dependencies = [ - "anyhow", - "bech32", - "itertools", - "nom", - "num-traits", - "rand 0.8.5", - "serde", - "snarkvm-curves", - "snarkvm-fields", - "snarkvm-utilities", - "zeroize", -] - -[[package]] -name = "snarkvm-console-program" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223979a6c22c2e25eda6c501668da9df954f9a87a982516b0c982b514766f232" -dependencies = [ - "enum_index", - "enum_index_derive", - "indexmap 2.0.0", - "num-derive 0.4.0", - "num-traits", - "once_cell", - "paste", - "serde_json", - "snarkvm-console-account", - "snarkvm-console-algorithms", - "snarkvm-console-collections", - "snarkvm-console-network", - "snarkvm-console-types", - "snarkvm-utilities", -] - -[[package]] -name = "snarkvm-console-types" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ebb8bdbdd728437c7f5b611cc2a03015c3ae015bfd0618956d81d25b2da4ce2" -dependencies = [ - "snarkvm-console-network-environment", - "snarkvm-console-types-address", - "snarkvm-console-types-boolean", - "snarkvm-console-types-field", - "snarkvm-console-types-group", - "snarkvm-console-types-integers", - "snarkvm-console-types-scalar", - "snarkvm-console-types-string", -] - -[[package]] -name = "snarkvm-console-types-address" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b29ac58056051bbb57a5ef49682d1a3bf482b9f2e442307fb081f4a5ca1b2f83" -dependencies = [ - "snarkvm-console-network-environment", - "snarkvm-console-types-boolean", - "snarkvm-console-types-field", - "snarkvm-console-types-group", -] - -[[package]] -name = "snarkvm-console-types-boolean" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e935a2a68edc8b5be8a0d211dc52c9cca95cb8a343ca102cb73cce5ef03cdff" -dependencies = [ - "snarkvm-console-network-environment", -] - -[[package]] -name = "snarkvm-console-types-field" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475b3857782cbb98ed8191a69e96f50726fdfc02769b6793eef9af1f3f76e2f4" -dependencies = [ - "snarkvm-console-network-environment", - "snarkvm-console-types-boolean", - "zeroize", -] - -[[package]] -name = "snarkvm-console-types-group" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a46244de03e589b46dbcb29672f34923d541e58d91801764e8c9da3bcc9ee7b7" -dependencies = [ - "snarkvm-console-network-environment", - "snarkvm-console-types-boolean", - "snarkvm-console-types-field", - "snarkvm-console-types-scalar", -] - -[[package]] -name = "snarkvm-console-types-integers" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9bee7bf0b1d3295cebeada300985bc382a91771159b33f1c43e9627e98b37ec" -dependencies = [ - "snarkvm-console-network-environment", - "snarkvm-console-types-boolean", - "snarkvm-console-types-field", - "snarkvm-console-types-scalar", -] - -[[package]] -name = "snarkvm-console-types-scalar" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a1e523a27f49a4db21eba6514f9f12dd739a30d440cdb4e4d93a4ae6e2d368" -dependencies = [ - "snarkvm-console-network-environment", - "snarkvm-console-types-boolean", - "snarkvm-console-types-field", - "zeroize", -] - -[[package]] -name = "snarkvm-console-types-string" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595994b88e0c0b91e20c4f810e2b70d2c6aac8d92c016ca2fd6db38647a5f28f" -dependencies = [ - "snarkvm-console-network-environment", - "snarkvm-console-types-boolean", - "snarkvm-console-types-field", - "snarkvm-console-types-integers", -] - -[[package]] -name = "snarkvm-curves" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd462a08bd74e09b7bc2c97e56d6706ae44f81ccbd52a16aed0d303a9f794e8" -dependencies = [ - "rand 0.8.5", - "rayon", - "rustc_version", - "serde", - "snarkvm-fields", - "snarkvm-utilities", - "thiserror", -] - -[[package]] -name = "snarkvm-fields" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8767f827e60eb2e26e7fa36b7b19e75096765c6ec5cf659073a28de60a6e269" -dependencies = [ - "aleo-std", - "anyhow", - "itertools", - "num-traits", - "rand 0.8.5", - "rayon", - "serde", - "snarkvm-utilities", - "thiserror", - "zeroize", -] - -[[package]] -name = "snarkvm-ledger" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc018c528b1637aad00041ff54b44eeba6f0507820bcb7236f64b760ace323fa" -dependencies = [ - "aleo-std", - "anyhow", - "indexmap 2.0.0", - "parking_lot", - "rand 0.8.5", - "rayon", - "snarkvm-console", - "snarkvm-ledger-authority", - "snarkvm-ledger-block", - "snarkvm-ledger-coinbase", - "snarkvm-ledger-committee", - "snarkvm-ledger-narwhal", - "snarkvm-ledger-query", - "snarkvm-ledger-store", - "snarkvm-synthesizer", - "time", - "tracing", -] - -[[package]] -name = "snarkvm-ledger-authority" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b52a1f9fb06498c0815e8937bd6f5f0b270e2b065c887fc010c247f70a53cf" -dependencies = [ - "anyhow", - "rand 0.8.5", - "serde_json", - "snarkvm-console", - "snarkvm-ledger-narwhal-subdag", -] - -[[package]] -name = "snarkvm-ledger-block" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e3a43fcd45a835aeebaa140acd73d75d1fe138eaf1ebb985ab17856eb4b896" -dependencies = [ - "indexmap 2.0.0", - "rayon", - "serde_json", - "snarkvm-console", - "snarkvm-ledger-authority", - "snarkvm-ledger-coinbase", - "snarkvm-ledger-committee", - "snarkvm-ledger-narwhal-batch-header", - "snarkvm-ledger-narwhal-subdag", - "snarkvm-ledger-narwhal-transmission-id", - "snarkvm-synthesizer-program", - "snarkvm-synthesizer-snark", -] - -[[package]] -name = "snarkvm-ledger-coinbase" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83981c236674369fbfdb03be133628ec512ceb3c47277f5dc90983f39d37de94" -dependencies = [ - "aleo-std", - "anyhow", - "bincode", - "blake2", - "indexmap 2.0.0", - "rayon", - "serde_json", - "snarkvm-algorithms", - "snarkvm-console", - "snarkvm-curves", - "snarkvm-fields", - "snarkvm-synthesizer-snark", - "snarkvm-utilities", -] - -[[package]] -name = "snarkvm-ledger-committee" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bc2b8d00e9ab5de46dc071e3598285d8cf795d695172c0de17f78f37998c13" -dependencies = [ - "indexmap 2.0.0", - "serde_json", - "snarkvm-console", -] - -[[package]] -name = "snarkvm-ledger-narwhal" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64afd92dbbb468baca5eb7632542293d50ab94de0314045ddf9c2d1f97b8181b" -dependencies = [ - "snarkvm-ledger-narwhal-batch-certificate", - "snarkvm-ledger-narwhal-batch-header", - "snarkvm-ledger-narwhal-data", - "snarkvm-ledger-narwhal-subdag", - "snarkvm-ledger-narwhal-transmission", - "snarkvm-ledger-narwhal-transmission-id", -] - -[[package]] -name = "snarkvm-ledger-narwhal-batch-certificate" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae7f97eb5229a0667cd7cc4b69b118912c6e5544609d710c9f85f9fd6c31441e" -dependencies = [ - "indexmap 2.0.0", - "rayon", - "serde_json", - "snarkvm-console", - "snarkvm-ledger-narwhal-batch-header", - "snarkvm-ledger-narwhal-transmission-id", -] - -[[package]] -name = "snarkvm-ledger-narwhal-batch-header" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b36228488081fe641c36ad8db890d903df4b19fb9720891f1ca172a0d1bb39e" -dependencies = [ - "indexmap 2.0.0", - "serde_json", - "snarkvm-console", - "snarkvm-ledger-narwhal-transmission-id", -] - -[[package]] -name = "snarkvm-ledger-narwhal-data" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15315726d409003433d7e56dcedab7e86c9feb0dcaa3979966595ac7e30ec5ab" -dependencies = [ - "bytes", - "serde_json", - "snarkvm-console", - "tokio", -] - -[[package]] -name = "snarkvm-ledger-narwhal-subdag" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb2b721d792dc0a13a1b19de25f1cb3a5b8feaa9796005653b6d2278a6a7e78" -dependencies = [ - "indexmap 2.0.0", - "rayon", - "serde_json", - "snarkvm-console", - "snarkvm-ledger-narwhal-batch-certificate", - "snarkvm-ledger-narwhal-batch-header", - "snarkvm-ledger-narwhal-transmission-id", -] - -[[package]] -name = "snarkvm-ledger-narwhal-transmission" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1670202f2a6897e14327ecc41613f64ecf3020628e448f67d1787615e11c59" -dependencies = [ - "bytes", - "serde_json", - "snarkvm-console", - "snarkvm-ledger-block", - "snarkvm-ledger-coinbase", - "snarkvm-ledger-narwhal-data", -] - -[[package]] -name = "snarkvm-ledger-narwhal-transmission-id" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126131b95a5506266aeea28952666ae10e6e91b9d272207d83ff3c10847b8d85" -dependencies = [ - "snarkvm-console", - "snarkvm-ledger-coinbase", -] - -[[package]] -name = "snarkvm-ledger-query" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7486798046553f092123c4f228ac4e6dd98fbffa313b32d1f20e619d633fbd7b" -dependencies = [ - "async-trait", - "reqwest", - "snarkvm-console", - "snarkvm-ledger-store", - "snarkvm-synthesizer-program", - "ureq", -] - -[[package]] -name = "snarkvm-ledger-store" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a5d648ec1a58194545393b1e3c0120dbcc4407b0f3cc207a15e680082f7d94" -dependencies = [ - "anyhow", - "bincode", - "indexmap 2.0.0", - "parking_lot", - "rayon", - "serde", - "snarkvm-console", - "snarkvm-ledger-authority", - "snarkvm-ledger-block", - "snarkvm-ledger-coinbase", - "snarkvm-ledger-committee", - "snarkvm-ledger-narwhal-batch-certificate", - "snarkvm-synthesizer-program", - "snarkvm-synthesizer-snark", -] - -[[package]] -name = "snarkvm-parameters" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4d47484bc6c0dfc526becaa37bcb85ba6b61782250b74a104d0ae85243e0caa" -dependencies = [ - "aleo-std", - "anyhow", - "bincode", - "cfg-if", - "colored", - "curl", - "hex", - "indexmap 2.0.0", - "itertools", - "lazy_static", - "parking_lot", - "paste", - "rand 0.8.5", - "serde_json", - "sha2", - "snarkvm-curves", - "snarkvm-utilities", - "thiserror", -] - -[[package]] -name = "snarkvm-synthesizer" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bef8cbc0d9106e43f4ff97235f24c0800f51a3854780a2b7d93abc09ea603cd" -dependencies = [ - "aleo-std", - "anyhow", - "indexmap 2.0.0", - "parking_lot", - "rand 0.8.5", - "rayon", - "snarkvm-algorithms", - "snarkvm-circuit", - "snarkvm-console", - "snarkvm-ledger-block", - "snarkvm-ledger-coinbase", - "snarkvm-ledger-committee", - "snarkvm-ledger-query", - "snarkvm-ledger-store", - "snarkvm-synthesizer-process", - "snarkvm-synthesizer-program", - "snarkvm-synthesizer-snark", - "tracing", -] - -[[package]] -name = "snarkvm-synthesizer-process" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de1ede93f4c3927c0a97db2fb84b7f5e8226e6db6e5b7edb9ba1ae85c3283168" -dependencies = [ - "aleo-std", - "colored", - "indexmap 2.0.0", - "once_cell", - "parking_lot", - "rand 0.8.5", - "rayon", - "serde_json", - "snarkvm-circuit", - "snarkvm-console", - "snarkvm-ledger-block", - "snarkvm-ledger-query", - "snarkvm-ledger-store", - "snarkvm-synthesizer-program", - "snarkvm-synthesizer-snark", - "snarkvm-utilities", -] - -[[package]] -name = "snarkvm-synthesizer-program" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "004af9b2cbad5740a72ecf5498cada2909403d0121a2709964967e9887049cd5" -dependencies = [ - "indexmap 2.0.0", - "paste", - "rand 0.8.5", - "rand_chacha 0.3.1", - "serde_json", - "snarkvm-circuit", - "snarkvm-console", -] - -[[package]] -name = "snarkvm-synthesizer-snark" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94eed0d284afc3620935f8772f7f6c5a857e2e9f3a7f0604477a5b09752bb42b" -dependencies = [ - "bincode", - "once_cell", - "serde_json", - "snarkvm-algorithms", - "snarkvm-circuit", - "snarkvm-console", -] - -[[package]] -name = "snarkvm-utilities" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23551bd2b97a7b65c1fa1348ed8269b3e3b39b31da279b978a1d0c8b33bb86b9" -dependencies = [ - "aleo-std", - "anyhow", - "bincode", - "num-bigint", - "num_cpus", - "rand 0.8.5", - "rand_xorshift", - "rayon", - "serde", - "serde_json", - "smol_str", - "snarkvm-utilities-derives", - "thiserror", - "zeroize", -] - -[[package]] -name = "snarkvm-utilities-derives" -version = "0.16.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6cf46ecfdc29202e7f185bbd4d18a5467dc644ed2add9b47234ce559bd8e956" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "socket2" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "softbuffer" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071916a85d1db274b4ed57af3a14afb66bd836ae7f82ebb6f1fd3455107830d9" -dependencies = [ - "as-raw-xcb-connection", - "bytemuck", - "cfg_aliases 0.2.0", - "cocoa", - "core-graphics", - "drm", - "fastrand 2.0.1", - "foreign-types 0.5.0", - "js-sys", - "log", - "memmap2", - "objc", - "raw-window-handle 0.6.0", - "redox_syscall 0.4.1", - "rustix 0.38.31", - "tiny-xlib", - "wasm-bindgen", - "wayland-backend", - "wayland-client", - "wayland-sys", - "web-sys", - "windows-sys 0.52.0", - "x11rb", -] - -[[package]] -name = "soup3" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" -dependencies = [ - "futures-channel", - "gio", - "glib", - "libc", - "soup3-sys", -] - -[[package]] -name = "soup3-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "ssss" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc8f7995380537ee49c88de8f05570ac35cb2953e8914017605dfb04c0078486" -dependencies = [ - "anyhow", - "getset", - "num-bigint", - "num-integer", - "num-traits", - "rand 0.8.5", - "rustversion", - "serde", - "thiserror", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "state" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" -dependencies = [ - "loom", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro2", - "quote 1.0.35", -] - -[[package]] -name = "strip-ansi-escapes" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" -dependencies = [ - "vte", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "swift-rs" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bbdb58577b6301f8d17ae2561f32002a5bae056d444e0f69e611e504a276204" -dependencies = [ - "base64", - "serde", - "serde_json", -] - -[[package]] -name = "syn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -dependencies = [ - "quote 0.3.15", - "synom", - "unicode-xid", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "unicode-ident", -] - -[[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "system-deps" -version = "6.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3" -dependencies = [ - "cfg-expr", - "heck", - "pkg-config", - "toml 0.7.4", - "version-compare", -] - -[[package]] -name = "tao" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa7ba6ee5b8908ba3a62e6a4f3683490ed732fca614cdd3f4c989bba548f9a9" -dependencies = [ - "bitflags 1.3.2", - "cc", - "cocoa", - "core-foundation", - "core-graphics", - "crossbeam-channel", - "dispatch", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", - "image", - "instant", - "jni", - "lazy_static", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc", - "once_cell", - "parking_lot", - "png", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.0", - "scopeguard", - "tao-macros", - "unicode-segmentation", - "url", - "windows 0.52.0", - "windows-implement", - "windows-version", - "x11-dl", - "zbus", -] - -[[package]] -name = "tao-macros" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec114582505d158b669b136e6851f85840c109819d77c42bb7c0709f727d18c2" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "tar" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "target-lexicon" -version = "0.12.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" - -[[package]] -name = "tauri" -version = "2.0.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a584d146c38bf174398dee0ec2cdd8f8fce142daee0306c370cf78f050304c60" -dependencies = [ - "anyhow", - "bytes", - "cocoa", - "dirs-next", - "embed_plist", - "futures-util", - "getrandom 0.2.10", - "glob", - "gtk", - "heck", - "http", - "jni", - "libc", - "log", - "mime", - "muda", - "nix", - "objc", - "percent-encoding", - "raw-window-handle 0.5.2", - "reqwest", - "serde", - "serde_json", - "serde_repr", - "serialize-to-javascript", - "state", - "static_assertions", - "swift-rs", - "tauri-build", - "tauri-macros", - "tauri-runtime", - "tauri-runtime-wry", - "tauri-utils", - "thiserror", - "tokio", - "tray-icon", - "url", - "webkit2gtk", - "webview2-com", - "window-vibrancy", - "windows 0.52.0", -] - -[[package]] -name = "tauri-build" -version = "2.0.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314089a25d92a62f33f60d2a19c277f465e9088ee3ea251032ae914d6f2b1ce0" -dependencies = [ - "anyhow", - "cargo_toml", - "dirs-next", - "glob", - "heck", - "json-patch", - "schemars", - "semver", - "serde", - "serde_json", - "tauri-utils", - "tauri-winres", - "toml 0.8.2", - "walkdir 2.3.3", -] - -[[package]] -name = "tauri-codegen" -version = "2.0.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6ff13874390499976f01decf75103f28e7609abc5c155c6bfb56cf574a5628" -dependencies = [ - "base64", - "brotli", - "ico", - "json-patch", - "plist", - "png", - "proc-macro2", - "quote 1.0.35", - "semver", - "serde", - "serde_json", - "sha2", - "tauri-utils", - "thiserror", - "time", - "url", - "uuid", - "walkdir 2.3.3", -] - -[[package]] -name = "tauri-macros" -version = "2.0.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18707774f70a8ec20dbf653f07d12af1e0d7c1e3a625b7bd5a2cfe72c2b2549b" -dependencies = [ - "heck", - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", - "tauri-codegen", - "tauri-utils", -] - -[[package]] -name = "tauri-plugin" -version = "2.0.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb732726fec855b56e4a238464f1b0c10006f618180ef402ce5f394d840e61b" -dependencies = [ - "anyhow", - "glob", - "plist", - "schemars", - "serde", - "serde_json", - "tauri-utils", - "toml 0.8.2", - "walkdir 1.0.7", -] - -[[package]] -name = "tauri-plugin-deep-link" -version = "2.0.0-beta.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c164394707e62f6df52785bc96aa3ee05d15170c7ea534a4fb61ccc26ba0b1" -dependencies = [ - "log", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror", - "url", -] - -[[package]] -name = "tauri-plugin-fs" -version = "2.0.0-beta.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd40ca5f99e9a4cbfcbd33de0f0b024caef6475f2652f1707cba72d877398a0" -dependencies = [ - "anyhow", - "glob", - "schemars", - "serde", - "serde_json", - "serde_repr", - "tauri", - "tauri-plugin", - "thiserror", - "url", - "uuid", -] - -[[package]] -name = "tauri-plugin-http" -version = "2.0.0-beta.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e427755fd9229027cc859ae0d19a5d2952a314792c16a25ce50c50eccd4a2db6" -dependencies = [ - "data-url", - "glob", - "http", - "reqwest", - "schemars", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-plugin-fs", - "thiserror", - "url", -] - -[[package]] -name = "tauri-plugin-updater" -version = "2.0.0-beta.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca006f95bd7ff80eb2749172c0faf9dc1e27eea20f289a759235753b8a0aabf8" -dependencies = [ - "base64", - "dirs-next", - "flate2", - "futures-util", - "http", - "minisign-verify", - "percent-encoding", - "reqwest", - "semver", - "serde", - "serde_json", - "tar", - "tauri", - "tauri-plugin", - "tempfile", - "thiserror", - "time", - "tokio", - "url", - "zip", -] - -[[package]] -name = "tauri-runtime" -version = "2.0.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d72194de56e885dbd9fd8c493ccf95012e584c928900188da248f9ea4223b23" -dependencies = [ - "gtk", - "http", - "jni", - "raw-window-handle 0.5.2", - "serde", - "serde_json", - "tauri-utils", - "thiserror", - "url", - "windows 0.52.0", -] - -[[package]] -name = "tauri-runtime-wry" -version = "2.0.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a71bd248a7ce857835b1f65845a9de22171e30d8129e018b42961502565efb" -dependencies = [ - "cocoa", - "gtk", - "http", - "jni", - "nix", - "percent-encoding", - "raw-window-handle 0.5.2", - "softbuffer", - "tao", - "tauri-runtime", - "tauri-utils", - "webkit2gtk", - "webview2-com", - "windows 0.52.0", - "wry", -] - -[[package]] -name = "tauri-utils" -version = "2.0.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7104f0639a1f3a7ebd7aac793be47d7924f569e7c10c6853083529bf9bb3fe6" -dependencies = [ - "brotli", - "cargo_metadata", - "ctor", - "dunce", - "glob", - "heck", - "html5ever", - "infer", - "json-patch", - "kuchikiki", - "log", - "memchr", - "phf 0.11.2", - "proc-macro2", - "quote 1.0.35", - "schemars", - "semver", - "serde", - "serde_json", - "serde_with", - "swift-rs", - "thiserror", - "toml 0.8.2", - "url", - "walkdir 2.3.3", -] - -[[package]] -name = "tauri-winres" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb" -dependencies = [ - "embed-resource", - "toml 0.7.4", -] - -[[package]] -name = "tempfile" -version = "3.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" -dependencies = [ - "cfg-if", - "fastrand 2.0.1", - "redox_syscall 0.3.5", - "rustix 0.38.31", - "windows-sys 0.48.0", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tid-rs" -version = "0.1.1" -source = "git+https://github.com/Zack-Xb/tid-rs#5cfee74f42b6edb2f3e10f8dbb77fe51be284659" -dependencies = [ - "cc", - "core-foundation", - "num", - "num-derive 0.3.3", - "num-traits", - "parking_lot", - "thiserror", -] - -[[package]] -name = "time" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" -dependencies = [ - "itoa 1.0.6", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" - -[[package]] -name = "time-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" -dependencies = [ - "time-core", -] - -[[package]] -name = "tiny-bip39" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" -dependencies = [ - "anyhow", - "hmac", - "once_cell", - "pbkdf2", - "rand 0.8.5", - "rustc-hash", - "sha2", - "thiserror", - "unicode-normalization", - "wasm-bindgen", - "zeroize", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tiny-xlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4098d49269baa034a8d1eae9bd63e9fa532148d772121dace3bcd6a6c98eb6d" -dependencies = [ - "as-raw-xcb-connection", - "ctor", - "libloading 0.8.1", - "tracing", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.5.4", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.19.10", -] - -[[package]] -name = "toml" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.20.2", -] - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" -dependencies = [ - "indexmap 1.9.3", - "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.4.7", -] - -[[package]] -name = "toml_edit" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" -dependencies = [ - "indexmap 2.0.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.5.34", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "tracing-core" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "tray-icon" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad962d06d2bfd9b2ab4f665fc73b175523b834b1466a294520201c5845145f8" -dependencies = [ - "cocoa", - "core-graphics", - "crossbeam-channel", - "dirs-next", - "libappindicator", - "muda", - "objc", - "once_cell", - "png", - "serde", - "thiserror", - "windows-sys 0.52.0", -] - -[[package]] -name = "treediff" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52984d277bdf2a751072b5df30ec0377febdb02f7696d64c2d7d54630bac4303" -dependencies = [ - "serde_json", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "uds_windows" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" -dependencies = [ - "tempfile", - "winapi 0.3.9", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - -[[package]] -name = "unicode-ident" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "ureq" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9" -dependencies = [ - "base64", - "flate2", - "log", - "once_cell", - "rustls", - "rustls-webpki 0.100.3", - "serde", - "serde_json", - "url", - "webpki-roots", -] - -[[package]] -name = "url" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" -dependencies = [ - "form_urlencoded", - "idna 0.4.0", - "percent-encoding", - "serde", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "uuid" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" -dependencies = [ - "getrandom 0.2.10", - "rand 0.8.5", - "serde", - "uuid-macro-internal", -] - -[[package]] -name = "uuid-macro-internal" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e1ba1f333bd65ce3c9f27de592fcbc256dafe3af2717f56d7c87761fbaccf4" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version-compare" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "vswhom" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" -dependencies = [ - "libc", - "vswhom-sys", -] - -[[package]] -name = "vswhom-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "vte" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" -dependencies = [ - "utf8parse", - "vte_generate_state_changes", -] - -[[package]] -name = "vte_generate_state_changes" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" -dependencies = [ - "proc-macro2", - "quote 1.0.35", -] - -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - -[[package]] -name = "walkdir" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" -dependencies = [ - "kernel32-sys", - "same-file 0.1.3", - "winapi 0.2.8", -] - -[[package]] -name = "walkdir" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" -dependencies = [ - "same-file 1.0.6", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[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.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" -dependencies = [ - "quote 1.0.35", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" - -[[package]] -name = "wasm-streams" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wayland-backend" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40" -dependencies = [ - "cc", - "downcast-rs", - "rustix 0.38.31", - "scoped-tls", - "smallvec", - "wayland-sys", -] - -[[package]] -name = "wayland-client" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" -dependencies = [ - "bitflags 2.4.0", - "rustix 0.38.31", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283" -dependencies = [ - "proc-macro2", - "quick-xml 0.31.0", - "quote 1.0.35", -] - -[[package]] -name = "wayland-sys" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" -dependencies = [ - "dlib", - "log", - "once_cell", - "pkg-config", -] - -[[package]] -name = "web-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webkit2gtk" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" -dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "gdk", - "gdk-sys", - "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", - "gtk", - "gtk-sys", - "javascriptcore-rs", - "libc", - "once_cell", - "soup3", - "webkit2gtk-sys", -] - -[[package]] -name = "webkit2gtk-sys" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" -dependencies = [ - "bitflags 1.3.2", - "cairo-sys-rs", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "gtk-sys", - "javascriptcore-rs-sys", - "libc", - "pkg-config", - "soup3-sys", - "system-deps", -] - -[[package]] -name = "webpki-roots" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" -dependencies = [ - "rustls-webpki 0.100.3", -] - -[[package]] -name = "webview2-com" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ae9c7e420783826cf769d2c06ac9ba462f450eca5893bb8c6c6529a4e5dd33" -dependencies = [ - "webview2-com-macros", - "webview2-com-sys", - "windows 0.52.0", - "windows-core", - "windows-implement", - "windows-interface", -] - -[[package]] -name = "webview2-com-macros" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "webview2-com-sys" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ad85fceee6c42fa3d61239eba5a11401bf38407a849ed5ea1b407df08cca72" -dependencies = [ - "thiserror", - "windows 0.52.0", - "windows-core", -] - -[[package]] -name = "whoami" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "window-vibrancy" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af6abc2b9c56bd95887825a1ce56cde49a2a97c07e28db465d541f5098a2656c" -dependencies = [ - "cocoa", - "objc", - "raw-window-handle 0.5.2", - "windows-sys 0.52.0", - "windows-version", -] - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core", - "windows-implement", - "windows-interface", - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-implement" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "windows-interface" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows-version" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75aa004c988e080ad34aff5739c39d0312f4684699d6d71fc8a198d057b8b9b4" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winnow" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.5.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a1a57ff50e9b408431e8f97d5456f2807f8eb2a2cd79b06068fc87f8ecf189" -dependencies = [ - "cfg-if", - "winapi 0.3.9", -] - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "wry" -version = "0.35.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3016c47c9b6f7029a9da7cd48af8352327226bba0e955f3c92e2966651365a9" -dependencies = [ - "base64", - "block", - "cfg_aliases 0.1.1", - "cocoa", - "core-graphics", - "crossbeam-channel", - "dunce", - "gdkx11", - "gtk", - "html5ever", - "http", - "javascriptcore-rs", - "jni", - "kuchikiki", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc", - "objc_id", - "once_cell", - "raw-window-handle 0.5.2", - "serde", - "serde_json", - "sha2", - "soup3", - "tao-macros", - "thiserror", - "url", - "webkit2gtk", - "webkit2gtk-sys", - "webview2-com", - "windows 0.52.0", - "windows-implement", - "windows-version", - "x11-dl", -] - -[[package]] -name = "x11" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "x11-dl" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" -dependencies = [ - "libc", - "once_cell", - "pkg-config", -] - -[[package]] -name = "x11rb" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" -dependencies = [ - "as-raw-xcb-connection", - "gethostname", - "libc", - "libloading 0.8.1", - "once_cell", - "rustix 0.38.31", - "x11rb-protocol", -] - -[[package]] -name = "x11rb-protocol" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34" - -[[package]] -name = "xattr" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" -dependencies = [ - "libc", - "linux-raw-sys 0.4.13", - "rustix 0.38.31", -] - -[[package]] -name = "xdg" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" - -[[package]] -name = "xdg-home" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd" -dependencies = [ - "nix", - "winapi 0.3.9", -] - -[[package]] -name = "zbus" -version = "3.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31de390a2d872e4cd04edd71b425e29853f786dc99317ed72d73d6fcf5ebb948" -dependencies = [ - "async-broadcast", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-process", - "async-recursion", - "async-task", - "async-trait", - "blocking", - "byteorder", - "derivative", - "enumflags2", - "event-listener", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "nix", - "once_cell", - "ordered-stream", - "rand 0.8.5", - "serde", - "serde_repr", - "sha1", - "static_assertions", - "tracing", - "uds_windows", - "winapi 0.3.9", - "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "3.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote 1.0.35", - "regex", - "syn 1.0.109", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb80bb776dbda6e23d705cf0123c3b95df99c4ebeaec6c2599d4a5419902b4a9" -dependencies = [ - "serde", - "static_assertions", - "zvariant", -] - -[[package]] -name = "zeroize" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.49", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes 0.8.3", - "byteorder", - "bzip2", - "constant_time_eq 0.1.5", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2", - "sha1", - "time", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" -dependencies = [ - "cc", - "pkg-config", -] - -[[package]] -name = "zvariant" -version = "3.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44b291bee0d960c53170780af148dca5fa260a63cdd24f1962fa82e03e53338c" -dependencies = [ - "byteorder", - "enumflags2", - "libc", - "serde", - "static_assertions", - "zvariant_derive", -] - -[[package]] -name = "zvariant_derive" -version = "3.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 1.0.109", -] diff --git a/backend/Cargo.toml b/backend/Cargo.toml deleted file mode 100644 index c2e535d9..00000000 --- a/backend/Cargo.toml +++ /dev/null @@ -1,94 +0,0 @@ -[package] -name = "avail_wallet" -version = "0.0.1" -description = "A Tauri App" -authors = ["Avail"] -license = "" -repository = "" -edition = "2021" - -[lib] -name = "availx_lib" -crate-type = ["staticlib", "cdylib", "rlib"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[build-dependencies] -tauri-build = { version = "2.0.0-beta.1", features = [] } - - -[dependencies] -app_dirs = { package = "app_dirs2", version = "2.5" } -avail-common = { git = "https://github.com/availx/avail-lib", tag = "v0.5.0", features = [ - "snarkvm", -] } -bs58 = "0.5.0" -chrono = "0.4.26" -dirs = "5.0.1" -dotenv = "0.15.0" -fix-path-env = { git = "https://github.com/tauri-apps/fix-path-env-rs" } -futures = "0.3.28" -jni = { version = "0.21.1" } -keyring = "2.0.5" -libc = "0.2.147" -log = "0.4.19" -ndk-context = "0.1.1" -once_cell = "1.18.0" -openssl = { version = "0.10.36", features = ["vendored"] } -rand = "0.8.5" -rayon = "1.7.0" -rusqlite = { version = "0.29.0", features = ["bundled", "chrono"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -snarkvm = { version = "0.16.17", features = [] } -ssss = "0.2.0" -tauri = { version = "2.0.0-beta.1", features = [] } -tauri-plugin-deep-link = "2.0.0-beta" -tauri-plugin-http = { version = "2.0.0-beta", features = ["cookies"] } -tauri-plugin-updater = { version = "2.0.0-beta.0", features = [] } -tiny-bip39 = "1.0.0" -tokio = { version = "1.29.1", features = ["full"] } -ureq = { version = "2.7.1", features = ["json"] } -uuid = { version = "1.4.1", features = ["v4", "serde"] } -whoami = "1.4.1" -zeroize = { version = "1.7.0", features = [ - "aarch64", - "zeroize_derive", - "alloc", -] } - -[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] -keyring = "2.0.5" -security-framework = { git = "https://github.com/AvailX/rust-security-framework" } -security-framework-sys = { git = "https://github.com/AvailX/rust-security-framework" } -core-foundation = "0.9.3" -tid-rs = { git = "https://github.com/Zack-Xb/tid-rs" } - - -[profile.release] -opt-level = 3 -lto = "thin" -incremental = true - -[profile.bench] -opt-level = 3 -debug = false -rpath = false -lto = "thin" -incremental = true -debug-assertions = false - -[profile.dev] -opt-level = 2 -lto = "thin" -incremental = true - -[profile.test] - -[features] -# this feature is used for production builds or when `devPath` points to the filesystem -# DO NOT REMOVE!! -custom-protocol = ["tauri/custom-protocol"] - -[dev-dependencies] -rstest = "0.18.2" diff --git a/backend/build.rs b/backend/build.rs deleted file mode 100644 index 261851f6..00000000 --- a/backend/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - tauri_build::build(); -} diff --git a/backend/capabilities/capabilities.toml b/backend/capabilities/capabilities.toml deleted file mode 100644 index a0564439..00000000 --- a/backend/capabilities/capabilities.toml +++ /dev/null @@ -1,20 +0,0 @@ -"$schema" = "./schemas/desktop-schema.toml" -identifier = "main-capability" -description = "Capability for the main window" -windows = ["main", "walletConnect"] -permissions = [ - "path:default", - "event:default", - "event:allow-listen", - "window:default", - "window:allow-create", - "window:allow-close", - "window:allow-set-title", - "window:allow-destroy", - "webview:allow-create-webview-window", - "webview:default", - "app:default", - "resources:default", - "menu:default", - "tray:default", -] diff --git a/backend/icons/128x128.png b/backend/icons/128x128.png deleted file mode 100644 index 8b5259350f3d7da2597e2443a4430dfd82525072..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2837 zcmV+w3+nWVP)dihlk@@;HNt z56)HDMlh|yx*rW@GM1r+$)v>4`HBu@^Bjz#R5bIG6FCjgA|*Xr(Kggkj)+!_5`WKk42f%S{Tia^kzEw++9|FF zDBAs9s)_G&z%UYd;_F2GgN6rKZ~dQ>qri~i^#uxU-=X4%pKUO7S|EzrBM(w_d@og> z_@2{(5IKS|kt3ML>xKXd{GE%OqG@sn7`kxtQ|h~POS!?f0$!o|?>=5hJeCB)3) ze2qMd9wm!G3-7-m z4FA?GDFRzrJM@?%Lg1$(_KQ=o0MPnJ$UxNaEnsDaQEN%=^tqD z&!0H=(Q595V5D7;ppUIdxNdvE?K%K&jHpp1z7`(8CZ zz&r(>L56X`a3%tXjgJS=>%`9@D-jqMK-M4FMzVY+Mg@RA-y45(vJ!z&0eIuL2hV2c z**_W`4H**v5+T0N-x@rlf#1%NDU1jJsa@A|`X=cUGoGfNmv#Zbts%AR*&cO|slVPq zy8zJdd%9!j**|HI2eb+R=}sT?b&o89IeV3KqAeASo5$>z4WPoe`ou%^D&O6x^4%$` zf0M*Ql~u&I7v&XLQgZgc_kN?T?ogWmFzc07%^v38D+eE=%J`_vx8wV6fcp)vEl~01 zXB1w_t|AG>hX{0_MF5!Y#Eh3|FsZWk%OBF(p&xW@^j5$_V5++RY&PB6^6S&ICPb|o zEdnrI_yEJB>l&sYZDaXu3v!?Z|%m?~UIXGrs(r;%~tvR}MZ- zroc1RQAncP1DI<4aPjxvoXLDq2D||>cP7%eSd9d+t3;^>(6Jsv~?Am=Xaz zfXePhnE)_W)``hh)-9$4sxlZCz9 zRetQwmPM;G`?UtBD!TzC0?_IHWs=9TB~_iU{MxkEt^mv9RbagUTv~IVM5d)R3b*j# zr=$WU0^r{sBpt|yXfVU4n$;suYx4rC8l4gWET5U8yI)<9nK`6KRkc{OewT@7C3S$f zOGO-@G!cYA?cVE$<)lTND^DW^*Y@7o3`|MuLPe2nku(A0#RkNUB696}`=gGFENV}F z-^sqe89W2Ndnd6wUy^E2w34=wXcIsZjE&{^c;@NGkg@OWTWtfG%D5G))|G(I(x;)y zSH--G5dkEL13O%C#ZCDBf)qotPpdtgi;Wp2y7m-wQUFO1B*kKoHv`Wg(wx})4;~{g zpdL{NY|(K6G?R=Q@`SEf#=22}r!@!!Rm1KsQ(C+L3=!>6pDgnpz#;e!J=xNIAU6V#6|*=0C36UP z-A$6D)$i0ZnY*a^qtSY5H%EeSS^!8Kh3}WNZy_%ijEW0u0DwFwLQHhY1*eYBS2!mC zQ%2wF9^w)>WHDVlH6+Fv0mKV4ZQDy2UIAC^71j>ARls7s0BkjUGqG2|rWmLPbj2fB zD*#sv-%PyUpDRblSSNtIoD_m?0aM+m3tT;6Z)sbmyM;G{);{>cZ0`0I!Y~rK2OXaa zwU}wJ!UN=`)wjat4KgzqK)gMw-$gVVG8F)f4&(c+e-8S0bq8_ zCwc5es{oMO$0^_*d(kQYOze2Rw-Th2NkbJ8ChmG$dD)%k^%S1rNQ7QmatzRA!^WLwmsJN}~5I$pd;b%LPb^#`aO?c2NC-m;d z-3{?QVfgD3>b8p)0g>*$&{pHe;ND#G1PTS9X7}n=U`%hb@ndk0l|$xE6HAM_6GJo} z7lVFw<;)bh!t%?L&a4_%vt7L6b8MP%<+PBP`tWp`TtJBcLX8O#thRM=m=&)UwjDJ` z#@yC-NVKcNE8s%RqO1$h0b0MyJ8Xj_;+spzFK<6{HUW@9OFT9-zEnvo}lc z0q%T7szIM=bF0}d@eZUm0s$;h8Z>x-JRBCafxHSpOA0uLd-K-p?9$3Y04$vc@Hh)2 z1_AIJ4;YGmbJ{Mm`$kR)dBQ~{XJrBVB z)*ZdaU-2I)fQb6ek*BAKs3vV*_W*2SNel_*$`K< z097`Li11zVcwvnNSOBz-n5v1(Zm5>atX=)?UjFg&G*!m(EW z$lCoT@higtRX^~az**|X7kQpmZ)h)ob;Mi&;)0{(af$Q7?Z3Fyn>wlq#Qz9WhvH?K zJhmfRdvvT5?9fUEf#`FaA=lrfDjXL8#Fd0UZA07--x3RKu9+|Z~{dihlk@@;HNt z56)HDMlh|yx*rW@GM1r+$)v>4`HBu@^Bjz#R5bIG6FCjgA|*Xr(Kggkj)+!_5`WKk42f%S{Tia^kzEw++9|FF zDBAs9s)_G&z%UYd;_F2GgN6rKZ~dQ>qri~i^#uxU-=X4%pKUO7S|EzrBM(w_d@og> z_@2{(5IKS|kt3ML>xKXd{GE%OqG@sn7`kxtQ|h~POS!?f0$!o|?>=5hJeCB)3) ze2qMd9wm!G3-7-m z4FA?GDFRzrJM@?%Lg1$(_KQ=o0MPnJ$UxNaEnsDaQEN%=^tqD z&!0H=(Q595V5D7;ppUIdxNdvE?K%K&jHpp1z7`(8CZ zz&r(>L56X`a3%tXjgJS=>%`9@D-jqMK-M4FMzVY+Mg@RA-y45(vJ!z&0eIuL2hV2c z**_W`4H**v5+T0N-x@rlf#1%NDU1jJsa@A|`X=cUGoGfNmv#Zbts%AR*&cO|slVPq zy8zJdd%9!j**|HI2eb+R=}sT?b&o89IeV3KqAeASo5$>z4WPoe`ou%^D&O6x^4%$` zf0M*Ql~u&I7v&XLQgZgc_kN?T?ogWmFzc07%^v38D+eE=%J`_vx8wV6fcp)vEl~01 zXB1w_t|AG>hX{0_MF5!Y#Eh3|FsZWk%OBF(p&xW@^j5$_V5++RY&PB6^6S&ICPb|o zEdnrI_yEJB>l&sYZDaXu3v!?Z|%m?~UIXGrs(r;%~tvR}MZ- zroc1RQAncP1DI<4aPjxvoXLDq2D||>cP7%eSd9d+t3;^>(6Jsv~?Am=Xaz zfXePhnE)_W)``hh)-9$4sxlZCz9 zRetQwmPM;G`?UtBD!TzC0?_IHWs=9TB~_iU{MxkEt^mv9RbagUTv~IVM5d)R3b*j# zr=$WU0^r{sBpt|yXfVU4n$;suYx4rC8l4gWET5U8yI)<9nK`6KRkc{OewT@7C3S$f zOGO-@G!cYA?cVE$<)lTND^DW^*Y@7o3`|MuLPe2nku(A0#RkNUB696}`=gGFENV}F z-^sqe89W2Ndnd6wUy^E2w34=wXcIsZjE&{^c;@NGkg@OWTWtfG%D5G))|G(I(x;)y zSH--G5dkEL13O%C#ZCDBf)qotPpdtgi;Wp2y7m-wQUFO1B*kKoHv`Wg(wx})4;~{g zpdL{NY|(K6G?R=Q@`SEf#=22}r!@!!Rm1KsQ(C+L3=!>6pDgnpz#;e!J=xNIAU6V#6|*=0C36UP z-A$6D)$i0ZnY*a^qtSY5H%EeSS^!8Kh3}WNZy_%ijEW0u0DwFwLQHhY1*eYBS2!mC zQ%2wF9^w)>WHDVlH6+Fv0mKV4ZQDy2UIAC^71j>ARls7s0BkjUGqG2|rWmLPbj2fB zD*#sv-%PyUpDRblSSNtIoD_m?0aM+m3tT;6Z)sbmyM;G{);{>cZ0`0I!Y~rK2OXaa zwU}wJ!UN=`)wjat4KgzqK)gMw-$gVVG8F)f4&(c+e-8S0bq8_ zCwc5es{oMO$0^_*d(kQYOze2Rw-Th2NkbJ8ChmG$dD)%k^%S1rNQ7QmatzRA!^WLwmsJN}~5I$pd;b%LPb^#`aO?c2NC-m;d z-3{?QVfgD3>b8p)0g>*$&{pHe;ND#G1PTS9X7}n=U`%hb@ndk0l|$xE6HAM_6GJo} z7lVFw<;)bh!t%?L&a4_%vt7L6b8MP%<+PBP`tWp`TtJBcLX8O#thRM=m=&)UwjDJ` z#@yC-NVKcNE8s%RqO1$h0b0MyJ8Xj_;+spzFK<6{HUW@9OFT9-zEnvo}lc z0q%T7szIM=bF0}d@eZUm0s$;h8Z>x-JRBCafxHSpOA0uLd-K-p?9$3Y04$vc@Hh)2 z1_AIJ4;YGmbJ{Mm`$kR)dBQ~{XJrBVB z)*ZdaU-2I)fQb6ek*BAKs3vV*_W*2SNel_*$`K< z097`Li11zVcwvnNSOBz-n5v1(Zm5>atX=)?UjFg&G*!m(EW z$lCoT@higtRX^~az**|X7kQpmZ)h)ob;Mi&;)0{(af$Q7?Z3Fyn>wlq#Qz9WhvH?K zJhmfRdvvT5?9fUEf#`FaA=lrfDjXL8#Fd0UZA07--x3RKu9+|Z~{eXu)D zds(i{K<*(k_!|*D@6lPBJNpPeS&{_2Ab%&uI@AfI36S5TV99S4EAZKn2+k#IZAC$x=i_)V|OmqxRSb>LWnRDV>42_nNc*3BmCtdDb&8hTs)7 zdjTmobZ`?ddBm9WB|npad1 z;0xs=DmB+zUjMz*?!`=8*Tj9$fb|vsCHyVG-bUw_!lTuF&RDe`Yiwe002ovPDHLk FV1f!EiNpW^ diff --git a/backend/icons/icon.icns b/backend/icons/icon.icns deleted file mode 100644 index 9842e74308b41d7ffc5bfe3e3e0633e319c8e29d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3890 zcmeHJF;62$82x5;4GVkNJGGltcN zDJUivLp&Ra2Bmeu4?xNvK>G{uKbX8(bA*PwTPYpamXxZPte>kHdyclOPfcWnVFto8MDtR{a#S| zkkcG09F)=gfhHgf$DT22oXtFI3Nm|~o;7r>r)wL67P>%TOt-OY8WX*@wWAl^1;p9G zjy`9z>1{z)htoU~c8{k_D=mbHgn>ln5XH0moE)H>GmzO4$LMW#u5PorRGrhpjtIbE zp()IaWpadl9ljGhGlxL)?u+-F>>~l%^ML?S>le}06g)BO*w)Okten%iOnjDBUV$=a)hMdPz z8AdFe7H|Y9&v}D}yh$H;`(E}A@zm4|9MXGqqB?Y{S~OG*I#=5?Qg!^*C{&E_K{QtO zWLPcag>Va-XOrI)kE$*N+>CxzEN~%r`&h9_333;rBgLXT?+x4U&UsVR1~0lA}|qD`DmA@X!B)Gc*^(qkLT7BHFkiq3Fg`Dhmq7p(`rVwWWd zIqYD0BsO{~6%9*5L`Y1K$RDEka$iv%DEACxAh+U^%b>Q&tHD2YMJ4DB5+&%J4T)X&y{8?xm*`-ahu$%N&~53Cp!bx% zJEaeW6@3eeZOuK7z>Q+!apZz=UNheT65o_C2cN&8#hoZnH&zJ>L$x8)JB5lTO6yq* z1Ifcs;zbX`6N!%&v5W8&vx^4N#Zb}(UiFJ}jCHJtF~sX0j-(OB0}tsUMADb`pi*AU z36Wh~tqgvaY!vQE9+b0?b2ZolWKXiSEDZ4aShB$~46qm+NfzW_fLzd*v@(lk^G(SPVQ}3%!@SKw(^IW7!v&417ry7$6ty0+Pj< ztof2vS8!03j-)q8toCFosH_MPATdB9cZlNZzNF_sWzQtNfB_^QRM%^(yu7|&m$VE6 zfW$HkkXs8R!oCh+fZQ4aO&kW0vQA`{!JkHgVlm+XYW{(#h(v3U`$O;l5rXhbx z_CPZ&;YilC(C8HUvh(l{N#|Pd4@kfQcV@urFJ)|zQRvb7%J-W@a~9n_#h=DE>XGMm z>@R)9O~>N+5$Jt-T>P)X@$b{0nE1|Jg?s%8)Pt|C-MGN{Lby`b@eW@^X1a}!4T=wT z{Oq)-|7j+8#+<61I& zH_>&W)Kb#>BJq7h32uz8zEG3iryRBfGw{zy4^S;mX zUe1|wY8dCqZ(W_ized(Ij7q~W8bzebxK4!q>PN=Pt(@dK3}YM-Eg5O|hkMdpiWTw?-}T6xckoDw7YiET|K-L)*mAc=BXD{K|LoJ8+^5tFBL@ zzS%*;B{^Yx>uYhmF^l|g?$$%`GwfWpKCS#CR-S{x*7!r;nP^(=z)of0Iyqsx{V_}N z%j;;}f=}9Sf7F6){cFcbXA~dC#Dnj%F*0Rh&8=y0ZYGlx$If6yn~j4%m<9E`ylDI2 z_a;`f+MuqsLw^|4FnsFXwL9t4qkefs23z(gO2&V1FrjobHlL;7GjDr7j$vVq3)l5< zmv+q(7u&OOjQ$=`wcw2*+tkg<*u&%VP_xvpUn)N1$Q-nFrF=Qi`c;cuZ0NPn|4|ID zO069IErO#bBdWby`ZjK}P(|(%Yp?HGzgYZ`E znpsZ?hdy-2q2eZXzEV6$@u;a~n5^G!eN1uz~G9J}+E|#uzd~@f5PY$f@{a==$^XUYd zud-3GKw>U6KpZcuYB-jTx2_hRUNF5%0`T=6xB@xLN?<%EgH--)4XUjjGw zSZKXFh1QM~Ha=uw%U~P>pGRdqn0QM#Kk(9j!`Ew?>tS5#QS;zCWlZ=mKNODZe$He2 zz83`FlP|U}S{}atX^aW6H~f={fzP7oel~&aqjBFp&3R!$?)+w`yy$&g@SCo5F!XKs zKECgZDDLb};_@48l~3lF?Zd){cEfNr|3g2TSh>!>|C3A0O=;P)3V+LKf77m{`u?%T z)S8yMs+5}B_IhdGV8*`pa2ypE_}2>U-Tp)})CcPB`XGh{)vl^%z1En!C6_vQax$j$ zXNm*+D1D;eAbIxYo@;|PIYx{^F{J(xIk#Nh?*9gp2kq4_b5vcw{B`aeqcM4=;dk}^ z7ZX_A6u=f;#-285n>vN?*-w6b@5j_065LbCVSafA7hmCE{pOU4Cu6#=#7EqaIdWYMGdahv*uFGX>99(l-8XZq1vFDR0M&w)+w$Accyz}%< zz~mi>ccFs#dW<&d56=eN<9MIoTI6|mfBAgLgpQ4fS~FlRUgq xs-DcF-}IN5#@qROu-GCO-UW|~oXh)n4`VKPf^8X-hGF*cUj+a24>2bN`yZJ*qYD54 diff --git a/backend/icons/icon.png b/backend/icons/icon.png deleted file mode 100644 index 8b5259350f3d7da2597e2443a4430dfd82525072..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2837 zcmV+w3+nWVP)dihlk@@;HNt z56)HDMlh|yx*rW@GM1r+$)v>4`HBu@^Bjz#R5bIG6FCjgA|*Xr(Kggkj)+!_5`WKk42f%S{Tia^kzEw++9|FF zDBAs9s)_G&z%UYd;_F2GgN6rKZ~dQ>qri~i^#uxU-=X4%pKUO7S|EzrBM(w_d@og> z_@2{(5IKS|kt3ML>xKXd{GE%OqG@sn7`kxtQ|h~POS!?f0$!o|?>=5hJeCB)3) ze2qMd9wm!G3-7-m z4FA?GDFRzrJM@?%Lg1$(_KQ=o0MPnJ$UxNaEnsDaQEN%=^tqD z&!0H=(Q595V5D7;ppUIdxNdvE?K%K&jHpp1z7`(8CZ zz&r(>L56X`a3%tXjgJS=>%`9@D-jqMK-M4FMzVY+Mg@RA-y45(vJ!z&0eIuL2hV2c z**_W`4H**v5+T0N-x@rlf#1%NDU1jJsa@A|`X=cUGoGfNmv#Zbts%AR*&cO|slVPq zy8zJdd%9!j**|HI2eb+R=}sT?b&o89IeV3KqAeASo5$>z4WPoe`ou%^D&O6x^4%$` zf0M*Ql~u&I7v&XLQgZgc_kN?T?ogWmFzc07%^v38D+eE=%J`_vx8wV6fcp)vEl~01 zXB1w_t|AG>hX{0_MF5!Y#Eh3|FsZWk%OBF(p&xW@^j5$_V5++RY&PB6^6S&ICPb|o zEdnrI_yEJB>l&sYZDaXu3v!?Z|%m?~UIXGrs(r;%~tvR}MZ- zroc1RQAncP1DI<4aPjxvoXLDq2D||>cP7%eSd9d+t3;^>(6Jsv~?Am=Xaz zfXePhnE)_W)``hh)-9$4sxlZCz9 zRetQwmPM;G`?UtBD!TzC0?_IHWs=9TB~_iU{MxkEt^mv9RbagUTv~IVM5d)R3b*j# zr=$WU0^r{sBpt|yXfVU4n$;suYx4rC8l4gWET5U8yI)<9nK`6KRkc{OewT@7C3S$f zOGO-@G!cYA?cVE$<)lTND^DW^*Y@7o3`|MuLPe2nku(A0#RkNUB696}`=gGFENV}F z-^sqe89W2Ndnd6wUy^E2w34=wXcIsZjE&{^c;@NGkg@OWTWtfG%D5G))|G(I(x;)y zSH--G5dkEL13O%C#ZCDBf)qotPpdtgi;Wp2y7m-wQUFO1B*kKoHv`Wg(wx})4;~{g zpdL{NY|(K6G?R=Q@`SEf#=22}r!@!!Rm1KsQ(C+L3=!>6pDgnpz#;e!J=xNIAU6V#6|*=0C36UP z-A$6D)$i0ZnY*a^qtSY5H%EeSS^!8Kh3}WNZy_%ijEW0u0DwFwLQHhY1*eYBS2!mC zQ%2wF9^w)>WHDVlH6+Fv0mKV4ZQDy2UIAC^71j>ARls7s0BkjUGqG2|rWmLPbj2fB zD*#sv-%PyUpDRblSSNtIoD_m?0aM+m3tT;6Z)sbmyM;G{);{>cZ0`0I!Y~rK2OXaa zwU}wJ!UN=`)wjat4KgzqK)gMw-$gVVG8F)f4&(c+e-8S0bq8_ zCwc5es{oMO$0^_*d(kQYOze2Rw-Th2NkbJ8ChmG$dD)%k^%S1rNQ7QmatzRA!^WLwmsJN}~5I$pd;b%LPb^#`aO?c2NC-m;d z-3{?QVfgD3>b8p)0g>*$&{pHe;ND#G1PTS9X7}n=U`%hb@ndk0l|$xE6HAM_6GJo} z7lVFw<;)bh!t%?L&a4_%vt7L6b8MP%<+PBP`tWp`TtJBcLX8O#thRM=m=&)UwjDJ` z#@yC-NVKcNE8s%RqO1$h0b0MyJ8Xj_;+spzFK<6{HUW@9OFT9-zEnvo}lc z0q%T7szIM=bF0}d@eZUm0s$;h8Z>x-JRBCafxHSpOA0uLd-K-p?9$3Y04$vc@Hh)2 z1_AIJ4;YGmbJ{Mm`$kR)dBQ~{XJrBVB z)*ZdaU-2I)fQb6ek*BAKs3vV*_W*2SNel_*$`K< z097`Li11zVcwvnNSOBz-n5v1(Zm5>atX=)?UjFg&G*!m(EW z$lCoT@higtRX^~az**|X7kQpmZ)h)ob;Mi&;)0{(af$Q7?Z3Fyn>wlq#Qz9WhvH?K zJhmfRdvvT5?9fUEf#`FaA=lrfDjXL8#Fd0UZA07--x3RKu9+|Z~{() -> AleoAPIClient { - let dev_node_ip = env!("DEV_NODE_IP"); - let api_client = AleoAPIClient::::local_testnet3("3030", &dev_node_ip); - - api_client -} - -pub fn setup_client() -> AvailResult> { - let node_api_obscura = env!("TESTNET_API_OBSCURA"); - - println!("Node API Obscura: {:?}", node_api_obscura); - - let base_url = format!( - "https://aleo-testnet3.obscura.build/v1/{}", - node_api_obscura - ); - - let api_client = AleoAPIClient::::new(&base_url, "testnet3")?; - - Ok(api_client) -} - -/* --Solve Network Generic Global State-- */ -#[derive(Debug, Clone)] -pub struct AleoClient { - pub client: AleoAPIClient, -} - -impl AleoClient { - pub fn new() -> AvailResult { - let node_api_obscura = env!("MAINNET_API_OBSCURA"); - - let base_url = format!("https://aleo-mainnet.obscura.build/v1/{}", node_api_obscura); - - Ok(Self { - client: AleoAPIClient::::new(&base_url, "mainnet")?, - }) - } - - pub fn devnet() -> AvailResult { - let node_api_obscura = env!("DEVNET_API_OBSCURA"); - - let base_url = format!("https://aleo-devnet.obscura.build/v1/{}", node_api_obscura); - - Ok(Self { - client: AleoAPIClient::::new(&base_url, "devnet")?, - }) - } - - pub fn testnet3() -> AvailResult { - let node_api_obscura = env!("TESTNET_API_OBSCURA"); - - let base_url = format!( - "https://aleo-testnet3.obscura.build/v1/{}", - node_api_obscura - ); - - Ok(Self { - client: AleoAPIClient::::new(&base_url, "testnet3")?, - }) - } - - pub fn switch_network(network: &str) -> AvailResult<()> { - // Based on the network string, decide which network to switch to - let new_client = match network { - "testnet3" => { - update_network(EventNetwork::AleoTestnet); - AleoClient::::testnet3()? - } - //"devnet" => AleoClient::::devnet()?, - //"mainnet" => AleoClient::::mainnet()?, - _ => { - return Err(AvailError::new( - avail_common::errors::AvailErrorType::Network, - "Invalid network".to_string(), - "Invalid network".to_string(), - )) - } - }; - - // Acquire a write lock and update the ALEO_CLIENT - let mut aleo_client = ALEO_CLIENT.write().unwrap(); - *aleo_client = new_client; - - Ok(()) - } - - pub fn local_dev() -> AvailResult { - let dev_node_ip = env!("DEV_NODE_IP"); - - Ok(Self { - client: AleoAPIClient::local_testnet3("3030", &dev_node_ip), - }) - } - - pub fn get_instance(&self) -> &AleoAPIClient { - &self.client - } -} - -pub static ALEO_CLIENT: Lazy>> = - Lazy::new(|| RwLock::new(AleoClient::::testnet3().unwrap())); - -#[test] -fn test_new_client() { - let api_client = setup_client::().unwrap(); - let height = api_client.latest_height().unwrap(); - - println!("Height: {:?}", height); -} diff --git a/backend/src/api/client.rs b/backend/src/api/client.rs deleted file mode 100644 index 6699837c..00000000 --- a/backend/src/api/client.rs +++ /dev/null @@ -1,100 +0,0 @@ -use std::sync::{Arc, RwLock}; - -use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; -use once_cell::sync::Lazy; - -use crate::helpers::utils::HOST; -use tauri_plugin_http::reqwest; - -pub fn get_rm_client_with_session( - method: reqwest::Method, - path: &str, -) -> AvailResult { - let api = env!("API"); - - let client = reqwest::Client::new(); - let cookie_name = "id"; - - let session = match SESSION.get_session_token() { - Some(session) => session, - None => { - return Err(AvailError::new( - AvailErrorType::Validation, - "Session not found".to_string(), - "Session not found".to_string(), - )) - } - }; - - let cookie_value = format!("{}={}", cookie_name, session); - let url = format!("{}/encrypted_data/{}", api, path); - - let request = client - .request(method, url) - .header(reqwest::header::COOKIE, cookie_value); - Ok(request) -} - -pub fn get_um_client_with_session( - method: reqwest::Method, - path: &str, -) -> AvailResult { - let api = env!("API"); - - let client = reqwest::Client::new(); - let cookie_name = "id"; - - let session = match SESSION.get_session_token() { - Some(session) => session, - None => { - return Err(AvailError::new( - AvailErrorType::Validation, - "Session not found".to_string(), - "Session not found".to_string(), - )) - } - }; - - let cookie_value = format!("{}={}", cookie_name, session); - - let url = format!("{}/{}", api, path); - let request = client - .request(method, url) - .header(reqwest::header::COOKIE, cookie_value); - - Ok(request) -} - -// create a global state of a session string called SESSION - -#[derive(Debug)] -pub struct Session { - pub session: RwLock>, -} - -impl Session { - pub fn new() -> Self { - Self { - session: RwLock::new(None), - } - } - - pub fn set_session_token(&self, token: String) { - let mut token_write = self.session.write().unwrap(); - *token_write = Some(token); - } - - pub fn get_session_token(&self) -> Option { - let token_read = self.session.read().unwrap(); - token_read.clone() - } -} - -pub static SESSION: Lazy> = Lazy::new(|| Arc::new(Session::new())); - -#[test] -fn test_session() { - SESSION.set_session_token("test".to_string()); - let token = SESSION.get_session_token(); - assert_eq!(token, Some("test".to_string())); -} diff --git a/backend/src/api/encrypted_data.rs b/backend/src/api/encrypted_data.rs deleted file mode 100644 index 4b483e4c..00000000 --- a/backend/src/api/encrypted_data.rs +++ /dev/null @@ -1,704 +0,0 @@ -use snarkvm::{console::program::Itertools, prelude::Network}; -use std::str::FromStr; -use tauri_plugin_http::reqwest; -use uuid::Uuid; - -use crate::{ - api::client::get_rm_client_with_session, - models::pointers::message::TransactionMessage, - services::local_storage::{ - persistent_storage::{get_address_string, get_last_tx_sync, update_last_tx_sync}, - session::view::VIEWSESSION, - }, -}; - -use avail_common::{ - errors::{AvError, AvailError, AvailErrorType, AvailResult}, - models::{ - encrypted_data::{ - Data, DataRequest, EncryptedData, EncryptedDataRecord, EncryptedDataSyncRequest, - EncryptedDataUpdateRequest, PageRequest, - }, - traits::encryptable::EncryptedStruct, - }, -}; - -/* --ENCRYPTED DATA SERVICE-- */ - -/// update encrypted data by id -pub async fn update_data(data: Vec, idx: Vec) -> AvailResult { - const MAX_BATCH_SIZE: usize = 300; - - // Assuming data and idx have the same length - let batches = data.chunks(MAX_BATCH_SIZE); - let idx_batches = idx.chunks(MAX_BATCH_SIZE); - - for (batch, idx_batch) in batches.zip(idx_batches) { - let request = batch - .iter() - .enumerate() - .map(|(i, data)| { - let id = Uuid::from_str(&idx_batch[i])?; - Ok(EncryptedDataUpdateRequest { - id, - ciphertext: data.ciphertext.clone(), - nonce: data.nonce.clone(), - }) - }) - .collect::, AvailError>>()?; - - let res = get_rm_client_with_session(reqwest::Method::PUT, "data")? - .json(&request) - .send() - .await?; - - if res.status() == 200 { - let _result = res.text().await?; - } else if res.status() == 401 { - return Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )); - } else { - return Err(AvailError::new( - AvailErrorType::External, - "Error updating encrypted data record ".to_string(), - "Error updating backup data.".to_string(), - )); - } - } - - Ok("Updated Succesfully".to_string()) -} - -/// update transactions received to synced -pub async fn synced(ids: Vec) -> AvailResult { - let res = get_rm_client_with_session(reqwest::Method::PUT, "sync")? - .json(&ids) - .send() - .await?; - - if res.status() == 200 { - let result = res.text().await?; - Ok(result) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error syncing data".to_string(), - "Error syncing data".to_string(), - )) - } -} - -///recover_txs get all blocks, tx_in and tx_out back locally -pub async fn get_new_transaction_messages( -) -> AvailResult<(Vec>, Vec)> { - let address = get_address_string()?; - let last_sync_time = get_last_tx_sync()?; - - let request = EncryptedDataSyncRequest { - owner: address, - last_sync: last_sync_time, - }; - - let res = get_rm_client_with_session(reqwest::Method::POST, "txs_received")? - .json(&request) - .send() - .await?; - - if res.status() == 200 { - // update last sync time - update_last_tx_sync(chrono::Utc::now())?; - - let result: Vec = res.json().await?; - - println!("Enc Data {:?}", result); - let encrypted_txs = result - .clone() - .into_iter() - .map(|x| x.to_enrypted_struct::()) - .collect::>>>()?; - - let v_key = VIEWSESSION.get_instance::()?; - - let txs_in: Vec> = encrypted_txs - .into_iter() - .map(|x| x.decrypt(v_key)) - .collect::>, _>>()?; - - let ids = result - .into_iter() - .map(|x| { - x.id.ok_or_else(|| { - AvailError::new( - AvailErrorType::Internal, - "Transaction id not found".to_string(), - "Transaction Id not found".to_string(), - ) - }) - }) - .collect::, AvailError>>()?; - - Ok((txs_in, ids)) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error checking transaction messages".to_string(), - "Error checking transaction messages".to_string(), - )) - } -} - -pub async fn post_encrypted_data(request: Vec) -> AvailResult> { - const MAX_BATCH_SIZE: usize = 300; - let mut ids: Vec = Vec::new(); - - // Split the request into batches of MAX_BATCH_SIZE - let batches = request.chunks(MAX_BATCH_SIZE); - - for batch in batches { - let request = batch - .into_iter() - .map(|data| EncryptedDataRecord::from(data.to_owned())) - .collect::>(); - - let res = get_rm_client_with_session(reqwest::Method::POST, "data")? - .json(&request) - .send() - .await?; - - if res.status() == 200 { - let result = res.text().await?; - let batch_ids: Vec = serde_json::from_str(&result)?; - ids.extend(batch_ids); - } else if res.status() == 401 { - return Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )); - } else { - return Err(AvailError::new( - AvailErrorType::External, - "Error posting encrypted data ".to_string(), - "".to_string(), - )); - } - } - - Ok(ids) -} - -pub async fn send_transaction_in(request: EncryptedData) -> AvailResult { - let res = get_rm_client_with_session(reqwest::Method::POST, "tx_sent")? - .json(&EncryptedDataRecord::from(request)) - .send() - .await?; - - if res.status() == 200 { - let result = res.text().await?; - - Ok(result) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error posting encrypted data ".to_string(), - "".to_string(), - )) - } -} - -pub async fn delete_invalid_transactions_in(ids: Vec) -> AvailResult { - let res = get_rm_client_with_session(reqwest::Method::DELETE, "txs_in")? - .json(&ids) - .send() - .await?; - - if res.status() == 200 { - let result = res.text().await?; - - Ok(result) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error deleting invalid transaction messages".to_string(), - "Error deleting invalid transaction messages".to_string(), - )) - } -} - -pub async fn get_data_count() -> AvailResult { - let res = get_rm_client_with_session(reqwest::Method::GET, "data_count")? - .send() - .await?; - - if res.status() == 200 { - let result = res.text().await?; - let count = result.parse::()?; - Ok(count) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error getting encrypted data count".to_string(), - "Error getting encrypted data count".to_string(), - )) - } -} - -pub async fn recover_data(_address: &str) -> AvailResult { - let data_count = get_data_count().await?; - let pages = (data_count as f64 / 300.0).ceil() as i64; - - let mut encrypted_data: Vec = vec![]; - - for page in 0..pages { - let page_request = PageRequest { page }; - - let res = get_rm_client_with_session(reqwest::Method::GET, "recover_data")? - .json(&page_request) - .send() - .await?; - - if res.status() == 200 { - let result: Data = res.json().await?; - encrypted_data.push(result); - } else if res.status() == 401 { - return Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )); - } else { - return Err(AvailError::new( - AvailErrorType::External, - "Error recovering encrypted data ".to_string(), - "Error recovering encrypted data".to_string(), - )); - } - } - - let mut record_pointers: Vec = vec![]; - let mut transactions: Vec = vec![]; - let mut transitions: Vec = vec![]; - let mut deployments: Vec = vec![]; - - for data in encrypted_data { - record_pointers.extend(data.record_pointers); - transactions.extend(data.transactions); - transitions.extend(data.transitions); - deployments.extend(data.deployments); - } - - Ok(Data { - record_pointers, - transactions, - transitions, - deployments, - }) -} - -pub async fn delete_all_server_storage() -> AvailResult { - let res = get_rm_client_with_session(reqwest::Method::DELETE, "data")? - .send() - .await?; - - if res.status() == 200 { - let result = res.text().await?; - - Ok(result) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error deleting encrypted data records ".to_string(), - "Error deleting server side data.".to_string(), - )) - } -} - -pub async fn import_encrypted_data(request: DataRequest) -> AvailResult { - // check that every vector in data request does not exceed 75 - - let record_pointers = request.data.record_pointers.len(); - let transactions = request.data.transactions.len(); - let transitions = request.data.transitions.len(); - let deployments = request.data.deployments.len(); - - // if they exceed 300 in sum, then split into several DataRequest where the sum of the data vectors inside is less than 300 - if record_pointers + transactions + transitions + deployments > 300 { - let mut data_requests: Vec = vec![]; - - let mut record_pointers = request.data.record_pointers.clone(); - let mut transactions = request.data.transactions.clone(); - let mut transitions = request.data.transitions.clone(); - let mut deployments = request.data.deployments.clone(); - - while record_pointers.len() + transactions.len() + transitions.len() + deployments.len() - > 300 - { - let mut record_pointers_batch = record_pointers.split_off(75); - let mut transactions_batch = transactions.split_off(75); - let mut transitions_batch = transitions.split_off(75); - let mut deployments_batch = deployments.split_off(75); - - let data: Data = Data { - record_pointers: record_pointers.clone(), - transactions: transactions.clone(), - transitions: transitions.clone(), - deployments: deployments.clone(), - }; - - let data_request = DataRequest { - address: request.address.clone(), - data, - }; - - data_requests.push(data_request); - - record_pointers = record_pointers_batch; - transactions = transactions_batch; - transitions = transitions_batch; - deployments = deployments_batch; - } - - let data = Data { - record_pointers, - transactions, - transitions, - deployments, - }; - - let data_request = DataRequest { - address: request.address.clone(), - data, - }; - - data_requests.push(data_request); - - for data_request in data_requests { - let res = get_rm_client_with_session(reqwest::Method::POST, "import_data")? - .json(&data_request) - .send() - .await?; - - if res.status() != 200 { - return Err(AvailError::new( - AvailErrorType::External, - "Error importing encrypted data.".to_string(), - "Error backing up encrypted data.".to_string(), - )); - } - } - - Ok("Imported Succesfully".to_string()) - } else { - let res = get_rm_client_with_session(reqwest::Method::POST, "import_data")? - .json(&request) - .send() - .await?; - - if res.status() == 200 { - let result = res.text().await?; - Ok(result) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error importing encrypted data.".to_string(), - "Error backing up encrypted data.".to_string(), - )) - } - } -} - -#[cfg(test)] - -mod encrypted_data_api_tests { - use super::*; - use crate::api::encrypted_data::{delete_all_server_storage, post_encrypted_data}; - - use crate::services::local_storage::encrypted_data::{ - delete_user_encrypted_data, get_encrypted_data_by_flavour, initialize_encrypted_data_table, - }; - use crate::services::local_storage::persistent_storage::{ - delete_user_preferences, get_address, initial_user_preferences, - }; - use crate::services::local_storage::storage_api::records::{ - encrypt_and_store_records, get_test_record_pointer, - }; - - use crate::services::local_storage::session::view::VIEWSESSION; - - use crate::models::storage::languages::Languages; - - use avail_common::models::encrypted_data::EncryptedDataTypeCommon; - use snarkvm::prelude::{PrivateKey, Testnet3, ToBytes, ViewKey}; - - use avail_common::models::constants::*; - - //TODO - Update endpoints required to test transactions in - #[tokio::test] - async fn test_get_new_transaction_messages() { - let address = get_address_string().unwrap(); - println!("{}", address); - let result = get_new_transaction_messages::().await.unwrap(); - println!("{:?}", result); - } - - #[tokio::test] - async fn test_update_data() { - let encrypted_record = EncryptedData::new( - Some(Uuid::new_v4()), - "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px".to_string(), - "some ciphertext".to_string(), - "some nonce".to_string(), - EncryptedDataTypeCommon::Record, - None, - None, - None, - chrono::Utc::now(), - None, - None, - "testnet3".to_string(), - Some("record_name".to_string()), - Some(false), - None, - None, - None, - ); - - let updated_encrypted_record = EncryptedData::new( - Some(Uuid::new_v4()), - "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px".to_string(), - "some ciphertext".to_string(), - "some nonce".to_string(), - EncryptedDataTypeCommon::Record, - None, - None, - None, - chrono::Utc::now(), - None, - None, - "testnet3".to_string(), - Some("record_name".to_string()), - Some(false), - None, - None, - None, - ); - - let ids = post_encrypted_data(vec![encrypted_record]).await.unwrap(); - - let res = update_data(vec![updated_encrypted_record], ids) - .await - .unwrap(); - - println!("{:?}", res); - delete_all_server_storage().await.unwrap(); - } - - #[tokio::test] - async fn test_synced() { - let encrypted_record = EncryptedData::new( - Some(Uuid::new_v4()), - "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px".to_string(), - "some ciphertext".to_string(), - "some nonce".to_string(), - EncryptedDataTypeCommon::Record, - None, - None, - None, - chrono::Utc::now(), - None, - None, - "testnet3".to_string(), - Some("record_name".to_string()), - Some(false), - None, - None, - None, - ); - - post_encrypted_data(vec![encrypted_record.clone()]) - .await - .unwrap(); - let ids = vec![encrypted_record.id.unwrap()]; - - let result = synced(ids).await.unwrap(); - println!("{:?}", result); - delete_all_server_storage().await.unwrap(); - } - - #[tokio::test] - async fn test_post_encrypted_data() { - let encrypted_record = EncryptedData::new( - Some(Uuid::new_v4()), - "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px".to_string(), - "some ciphertext".to_string(), - "some nonce".to_string(), - EncryptedDataTypeCommon::Record, - None, - None, - None, - chrono::Utc::now(), - None, - None, - "testnet3".to_string(), - Some("record_name".to_string()), - Some(false), - None, - None, - None, - ); - - let res = post_encrypted_data(vec![encrypted_record]).await.unwrap(); - - println!("{:?}", res); - delete_all_server_storage().await.unwrap(); - } - - #[tokio::test] - async fn test_recover_data() { - let encrypted_record = EncryptedData::new( - Some(Uuid::new_v4()), - "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px".to_string(), - "some ciphertext".to_string(), - "some nonce".to_string(), - EncryptedDataTypeCommon::Record, - None, - None, - None, - chrono::Utc::now(), - None, - None, - "testnet3".to_string(), - Some("record_name".to_string()), - Some(false), - None, - None, - None, - ); - - let res = post_encrypted_data(vec![encrypted_record]).await.unwrap(); - - println!("{:?}", res); - let address = get_address_string().unwrap(); - - let result = recover_data(&address).await.unwrap(); - println!("{:?}", result); - delete_all_server_storage().await.unwrap(); - } - - #[tokio::test] - async fn test_delete_all() { - let result = delete_all_server_storage().await.unwrap(); - println!("{:?}", result); - } - - fn test_setup_prerequisites() { - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let view_key = ViewKey::::try_from(&pk).unwrap(); - - delete_user_encrypted_data().unwrap(); - - delete_user_preferences().unwrap(); - // initialize the user preferences - initial_user_preferences( - false, - None, - None, - false, - false, - view_key.to_address().to_string(), - Languages::English, - ) - .unwrap(); - initialize_encrypted_data_table().unwrap(); - - VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); - } - - #[tokio::test] - async fn test_import_encrypted_data() { - test_setup_prerequisites(); - let test_pointer = get_test_record_pointer(); - let address = get_address::().unwrap(); - - encrypt_and_store_records(vec![test_pointer], address).unwrap(); - - let encrypted_record_pointers = - get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record).unwrap(); - let backup_encrypted_records = encrypted_record_pointers - .iter() - .map(|encrypted_record| EncryptedDataRecord::from(encrypted_record.to_owned())) - .collect::>(); - - let encrypted_transactions = - get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transaction).unwrap(); - let backup_encrypted_transactions = encrypted_transactions - .iter() - .map(|encrypted_transaction| { - EncryptedDataRecord::from(encrypted_transaction.to_owned()) - }) - .collect::>(); - - let encrypted_deployments = - get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Deployment).unwrap(); - let backup_encrypted_deployments = encrypted_deployments - .iter() - .map(|encrypted_deployment| EncryptedDataRecord::from(encrypted_deployment.to_owned())) - .collect::>(); - - let encrypted_transitions = - get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transition).unwrap(); - let backup_encrypted_transitions = encrypted_transitions - .iter() - .map(|encrypted_transition| EncryptedDataRecord::from(encrypted_transition.to_owned())) - .collect::>(); - - let data = Data::new( - backup_encrypted_records, - backup_encrypted_transactions, - backup_encrypted_transitions, - backup_encrypted_deployments, - ); - - let address = get_address_string().unwrap(); - - let request = DataRequest { address, data }; - - let result = import_encrypted_data(request).await.unwrap(); - println!("{:?}", result); - - delete_all_server_storage().await.unwrap(); - } -} diff --git a/backend/src/api/fee.rs b/backend/src/api/fee.rs deleted file mode 100644 index 9756042a..00000000 --- a/backend/src/api/fee.rs +++ /dev/null @@ -1,176 +0,0 @@ -use tauri_plugin_http::reqwest; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::fee_request::FeeRequest, -}; - -/* - create_record(request) - A function to handle the API call to the Avail's Fee Estimation Microservice to add Fee Data to the database. - Inputs - A FeeRequest Struct with execution_object, program_id, function_id, network -*/ -pub async fn create_record(request: FeeRequest) -> AvailResult { - let client = reqwest::Client::new(); - - let res = client - .post(format!("http://localhost:8080/fee/create-record")) - .json(&request) - .send() - .await?; - - if res.status() == 200 { - let result = res.json().await?; - - Ok(result) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Fee record creation FAILED".to_string(), - "Fee estimation failed.".to_string(), - )) - } -} -/* - fetch_record(pid,fid) - A function to handle the API call to the Avail's Fee Estimation Microservice to fetch Fee Data from the database. - Inputs - program_id and function_id - Output - fee -*/ -pub async fn fetch_record(pid: String, fid: String) -> AvailResult> { - let client = reqwest::Client::new(); - - let res = client - .get(format!( - "http://localhost:8080/fee/fetch-record/{}/{}", - pid, fid - )) - .send() - .await?; - - if res.status() == 200 { - let result: Option = res.json().await?; - - Ok(result) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error getting fee.".to_string(), - "Error getting fee.".to_string(), - )) - } -} - -#[cfg(test)] - -mod tests { - use std::str::FromStr; - - use avail_common::aleo_tools::program_manager::ProgramManager; - use avail_common::models::{ - constants::{TESTNET3_ADDRESS, TESTNET3_PRIVATE_KEY}, - network::SupportedNetworks, - }; - use snarkvm::{ - circuit::AleoV0, - prelude::{Address, Execution, PrivateKey, Testnet3}, - }; - - use crate::api::aleo_client::{setup_client, setup_local_client}; - - use super::*; - - #[tokio::test] - async fn test_create_record() { - let new_exec = get_execution_object().await.unwrap(); - // let new_exec = Execution::::new(); - let exec_obj: Vec = FeeRequest::to_bytes_execution_object::(new_exec) - .await - .unwrap(); - // println!("{:?}", exec_obj); - let req: FeeRequest = FeeRequest::new( - exec_obj, - "testing.aleo".to_string(), - "testing_7".to_string(), - SupportedNetworks::Testnet3, - ); - println!("Sending req...."); - let result: String = create_record(req).await.unwrap(); - - println!("{:?}", result); - } - - #[tokio::test] - async fn test_fetch_fee_record() { - let result = fetch_record("testing.aleo".to_string(), "testing_6".to_string()) - .await - .unwrap(); - println!("{:?}", result); - } - - async fn get_execution_object() -> AvailResult> { - let pk = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); - let api_client = setup_client::().unwrap(); - let recipient = Address::::from_str(TESTNET3_ADDRESS).unwrap(); - - let program = api_client.get_program("credits.aleo").unwrap(); - - let program_manager = - ProgramManager::::new(Some(pk), None, Some(api_client), None).unwrap(); - - let (total, (_, _), execution) = program_manager - .estimate_execution_fee::( - &program, - "transfer_public_to_private", - vec![recipient.to_string(), "10000u64".to_string()].iter(), - ) - .unwrap(); - //println!("{:?} ... {:?}...{:?}",txn.id(),txn.fee_amount(),txn.base_fee_amount()); - //let exec_option = txn.execution(); - - println!("{:?}", total); - // let exec= exec_option.unwrap(); - //let ex = exec.clone(); - //println!("{:?}", ex.to_execution_id()); - //Ok(ex) - Ok(execution) - } - - #[tokio::test] - async fn test_get_execution_object() { - let pk = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); - let api_client = setup_client::().unwrap(); - let recipient = Address::::from_str(TESTNET3_ADDRESS).unwrap(); - - let program = api_client.get_program("credits.aleo").unwrap(); - - let program_manager = - ProgramManager::::new(Some(pk), None, Some(api_client), None).unwrap(); - - let (total, (_x, _y), _execution) = program_manager - .estimate_execution_fee::( - &program, - "transfer_public_to_private", - vec![recipient.to_string(), "10000u64".to_string()].iter(), - ) - .unwrap(); - //println!("{:?} ... {:?}...{:?}",txn.id(),txn.fee_amount(),txn.base_fee_amount()); - //let exec_option = txn.execution(); - - println!("{:?}", total); - // let exec= exec_option.unwrap(); - //let ex = exec.clone(); - //println!("{:?}", ex.to_execution_id()); - //Ok(ex) - } -} diff --git a/backend/src/api/tokens.rs b/backend/src/api/tokens.rs deleted file mode 100644 index 757cef3e..00000000 --- a/backend/src/api/tokens.rs +++ /dev/null @@ -1,52 +0,0 @@ -use tauri_plugin_http::reqwest; - -use crate::helpers::utils::HOST; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::tokens::Token, -}; -//TODO - Update for V2 - -/* --TOKENS-- */ - -/// Fetches list of tokens to be listed to user in ui, for example for swaps. -#[tokio::main(flavor = "current_thread")] -pub async fn get_token_list() -> AvailResult> { - let client = reqwest::Client::new(); - - let res = client - .get(format!("http://{}:8100/token", HOST)) - .send() - .await?; - - if res.status() == 200 { - let result: Vec = res.json().await?; - - Ok(result) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error getting token list.".to_string(), - "Error getting token list.".to_string(), - )) - } -} - -#[cfg(test)] - -mod tests { - use super::*; - - #[test] - fn test_get_token_list() { - let result = get_token_list().unwrap(); - println!("{:?}", result); - } -} diff --git a/backend/src/api/user.rs b/backend/src/api/user.rs deleted file mode 100644 index 4a124f28..00000000 --- a/backend/src/api/user.rs +++ /dev/null @@ -1,259 +0,0 @@ -use snarkvm::prelude::*; -use std::str::FromStr; -use tauri_plugin_http::reqwest; - -use crate::api::client::get_um_client_with_session; -use crate::helpers::utils::HOST; -use crate::helpers::validation::validate_address; -use crate::models::account::AddressRequest; -use crate::services::local_storage::persistent_storage::{ - get_backup_flag, update_local_backup_flag, -}; -use crate::services::{ - account::utils::generate_discriminant, - local_storage::persistent_storage::{get_address_string, update_username_local}, -}; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::user::{UpdateBackupRequest, User}, -}; - -/* --USER SERVICE-- */ - -// create user online account -pub async fn create_user(request: User) -> AvailResult { - let api = env!("API"); - - let client = reqwest::Client::new(); - - let res = client - .post(format!("{}/user", api)) - .json(&request) - .send() - .await?; - - if res.status() == 200 { - Ok("User created".to_string()) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error creating user".to_string(), - "Error creating user".to_string(), - )) - } -} - -// get user online account -pub async fn get_user() -> AvailResult { - let res = get_um_client_with_session(reqwest::Method::GET, "user")? - .send() - .await?; - - if res.status() == 200 { - let user: User = res.json().await?; - - Ok(user) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error getting user".to_string(), - "Error getting user".to_string(), - )) - } -} - -/// delete user on server-side -pub async fn delete_user() -> AvailResult { - let res = get_um_client_with_session(reqwest::Method::DELETE, "user")? - .send() - .await?; - - if res.status() == 200 { - Ok("User deleted".to_string()) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else if res.status() == 404 { - Ok("User not found".to_string()) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error deleting user account on server side.".to_string(), - "Error deleting online account.".to_string(), - )) - } -} - -//get aleo address from username -pub async fn name_to_address(username: &str) -> AvailResult> { - let _validation = match validate_address(username) { - Ok(_) => return Ok(Address::::from_str(username)?), - Err(_) => false, - }; - - let request = AddressRequest { - username: username.to_string(), - }; - - let res = get_um_client_with_session(reqwest::Method::GET, &format!("user_address"))? - .json(&request) - .send() - .await?; - - if res.status() == 200 { - let address: String = res.json().await?; - - print!("{}", address); - - let address = Address::::from_str(&address).unwrap(); - - Ok(address) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error getting address".to_string(), - "Error getting address".to_string(), - )) - } -} - -pub async fn get_username(address: &str) -> AvailResult> { - let res = get_um_client_with_session(reqwest::Method::GET, &format!("username/{}", address))? - .send() - .await?; - - if res.status() == 200 { - let username: Option = res.json().await?; - - Ok(username) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error getting username".to_string(), - "Error getting username".to_string(), - )) - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn update_username(username: &str) -> AvailResult { - let address = get_address_string()?; - let backup = get_backup_flag()?; - - let tag = generate_discriminant(); - - let res = get_um_client_with_session(reqwest::Method::PUT, "user")? - .json(&User::new( - Some(username.to_string()), - address, - Some(tag as u32), - backup, - )) - .send() - .await?; - - if res.status() == 200 { - update_username_local(username, tag as i32)?; - Ok("Username updated".to_string()) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error updating username".to_string(), - "Error updating username".to_string(), - )) - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn update_backup_flag(backup_flag: bool) -> AvailResult<()> { - let request = UpdateBackupRequest { - backup: backup_flag, - }; - - // TODO - Handle backup flag being false and server side backup being true - // Should backup get deleted on server side? - - let res = get_um_client_with_session(reqwest::Method::PUT, "backup")? - .json(&request) - .send() - .await?; - - if res.status() == 200 { - update_local_backup_flag(backup_flag)?; - Ok(()) - } else if res.status() == 401 { - Err(AvailError::new( - AvailErrorType::Unauthorized, - "User session has expired.".to_string(), - "Your session has expired, please authenticate again.".to_string(), - )) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Error updating username".to_string(), - "Error updating username".to_string(), - )) - } -} - -#[cfg(test)] - -mod tests { - use super::*; - - #[tokio::test] - async fn test_create_user() { - let address = "aleo1ckcdjd9wned6s9eqprf2km88znlmh2je03jg2ctxat5k4hllzuqq47j3zg".to_string(); - let username = Some("AvailInhabitantX".to_string()); - let tag = 1234; - - let request = User::new(username, address, Some(tag as u32), false); - - // let result = block_on(create_user(request)).unwrap(); - - let result = create_user(request).await.unwrap(); - println!("{:?}", result); - } - - #[tokio::test] - async fn test_name_to_address() { - let username = "AvailInhabitantX"; - - let result = name_to_address::(username).await.unwrap(); - println!("{:?}", result); - } - - #[tokio::test] - async fn test_delete_user() { - let result = delete_user().await.unwrap(); - println!("{:?}", result); - } -} diff --git a/backend/src/helpers.rs b/backend/src/helpers.rs deleted file mode 100644 index 8acefa98..00000000 --- a/backend/src/helpers.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod upgrade; -pub mod utils; -pub mod validation; diff --git a/backend/src/helpers/upgrade.rs b/backend/src/helpers/upgrade.rs deleted file mode 100644 index 69caa5e0..00000000 --- a/backend/src/helpers/upgrade.rs +++ /dev/null @@ -1,58 +0,0 @@ -/* THIS IS TO FACILITATE UPGRADING FROM A SEED PHRASE WALLET TO A NORMAL AVAIL WALLET */ - -use crate::{ - api::encrypted_data::import_encrypted_data, - services::local_storage::{encrypted_data::*, persistent_storage::get_address_string}, -}; -use avail_common::{ - errors::AvailResult, - models::encrypted_data::{Data, DataRequest, EncryptedDataRecord, EncryptedDataTypeCommon}, -}; - -pub async fn upgrade() -> AvailResult { - let encrypted_record_pointers = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record)?; - let backup_encrypted_records = encrypted_record_pointers - .iter() - .map(|encrypted_record| EncryptedDataRecord::from(encrypted_record.to_owned())) - .collect::>(); - - let encrypted_transactions = - get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transaction)?; - let backup_encrypted_transactions = encrypted_transactions - .iter() - .map(|encrypted_transaction| EncryptedDataRecord::from(encrypted_transaction.to_owned())) - .collect::>(); - - let encrypted_transitions = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transition)?; - let backup_encrypted_transitions = encrypted_transitions - .iter() - .map(|encrypted_transition| EncryptedDataRecord::from(encrypted_transition.to_owned())) - .collect::>(); - - let encrypted_deployments = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Deployment)?; - let backup_encrypted_deployments = encrypted_deployments - .iter() - .map(|encrypted_deployment| EncryptedDataRecord::from(encrypted_deployment.to_owned())) - .collect::>(); - - let data = Data::new( - backup_encrypted_records, - backup_encrypted_transactions, - backup_encrypted_transitions, - backup_encrypted_deployments, - ); - - let address = get_address_string()?; - - let request = DataRequest { address, data }; - - let res = import_encrypted_data(request).await?; - - Ok(res) -} - -#[tokio::test] -async fn test_upgrade() { - let res = upgrade().await.unwrap(); - println!("{:?}", res); -} diff --git a/backend/src/helpers/utils.rs b/backend/src/helpers/utils.rs deleted file mode 100644 index 136303cb..00000000 --- a/backend/src/helpers/utils.rs +++ /dev/null @@ -1,67 +0,0 @@ -use super::validation; -use chrono::{DateTime, Local, NaiveDateTime, Utc}; -use snarkvm::prelude::{Ciphertext, Network, PrivateKey}; - -use avail_common::{ - aleo_tools::encryptor::Encryptor, - errors::{AvailError, AvailErrorType, AvailResult}, -}; - -/// This should be moved to utils and will most likely be deprecated. -/// Deprication depends on android local storage. -pub fn encrypt_key(key: PrivateKey, secret: &str) -> AvailResult> { - validation::validate_private_key(&key.to_string())?; - validation::validate_secret_password(secret)?; - - let encrypted_private_key = Encryptor::::encrypt_private_key_with_secret(&key, secret)?; - - Ok(encrypted_private_key) -} - -///This should be moved to utils and will most likely be deprecated. -/// Deprication depends on android local storage. -pub fn decrypt_key( - ciphertext: &Ciphertext, - secret: &str, -) -> AvailResult> { - let decrypted_private_key = - Encryptor::::decrypt_private_key_with_secret(ciphertext, secret)?; - - Ok(decrypted_private_key) -} - -pub fn get_timestamp_from_i64(i: i64) -> AvailResult> { - let naive_time = match NaiveDateTime::from_timestamp_opt(i, 0) { - Some(naive_time) => naive_time, - None => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Invalid block timestamp".to_string(), - "Invalid block timestamp".to_string(), - )) - } - }; - - let timestamp_datetime: DateTime = - DateTime::::from_naive_utc_and_offset(naive_time, Local::now().offset().to_owned()); - Ok(timestamp_datetime) -} - -pub fn get_timestamp_from_i64_utc(i: i64) -> AvailResult> { - let naive_time = match NaiveDateTime::from_timestamp_opt(i, 0) { - Some(naive_time) => naive_time, - None => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Invalid block timestamp".to_string(), - "Invalid block timestamp".to_string(), - )) - } - }; - - let utc_timestamp = DateTime::::from_utc(naive_time, Utc); - - Ok(utc_timestamp) -} - -pub const HOST: &str = "localhost"; diff --git a/backend/src/helpers/validation.rs b/backend/src/helpers/validation.rs deleted file mode 100644 index 54e7649f..00000000 --- a/backend/src/helpers/validation.rs +++ /dev/null @@ -1,145 +0,0 @@ -use bs58; -use snarkvm::prelude::bech32; - -use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; - -/// Validates an aleo private key checking it's length and prefix. -pub fn validate_private_key(pk: &String) -> AvailResult<()> { - if pk.len() != 59 { - return Err(AvailError::new( - AvailErrorType::InvalidData, - format!("Invalid private key with length {} != 59", pk.len()), - "Invalid private key".to_string(), - )); - } - - if &pk[0..12] != "APrivateKey1" { - return Err(AvailError::new( - AvailErrorType::InvalidData, - format!("Invalid private key starting with {}", &pk[0..12]), - "Invalid private key".to_string(), - )); - } - - let base58 = &pk[12..59]; - let _base58_res = bs58::decode(base58).into_vec()?; - - Ok(()) -} - -pub fn validate_address(address: &str) -> AvailResult { - if address.len() != 63 { - return Err(AvailError::new( - AvailErrorType::InvalidData, - format!("Invalid address with length {} != 63", address.len()), - "Invalid address".to_string(), - )); - } - - if &address[0..5] != "aleo1" { - return Err(AvailError::new( - AvailErrorType::InvalidData, - format!("Invalid address starting with {}", &address[0..5]), - "Invalid address".to_string(), - )); - } - - let _bech32_res = bech32::decode(address)?; - - Ok(true) -} - -pub fn validate_address_bool(address: &str) -> bool { - if address.len() != 63 { - return false; - } - - if &address[0..5] != "aleo1" { - return false; - } - - let _bech32_res = bech32::decode(address); - - match _bech32_res { - Ok(_) => true, - Err(_) => false, - } -} - -pub fn validate_secret_password(secret: &str) -> AvailResult<()> { - if secret.len() < 12 { - return Err(AvailError::new( - AvailErrorType::Validation, - format!("Invalid secret with length {} < 12", secret.len()), - "Invalid secret".to_string(), - )); - } - - let mut has_num = false; - let mut has_cap = false; - let mut has_special = false; - - for c in secret.chars() { - if c.is_numeric() { - has_num = true; - } else if c.is_uppercase() { - has_cap = true; - } else if c.is_ascii_punctuation() { - has_special = true; - } - } - - if !has_num || !has_cap || !has_special { - return Err(AvailError::new( - AvailErrorType::Validation, - "Password too weak, must include at least one number, one uppercase character and one symbol.".to_string(), - "Password too weak, must include at least one number, one uppercase character and one symbol.".to_string(), - )); - } - - // TODO: Entropy check - Ok(()) -} - -#[test] -fn test_validate_private_key() { - let pk_str = "APrivateKey1zkp4X9ApjTb7Rv8EABfZRugXBhbPzCL245GyNtYJP5GYY2k"; - - let _res = validate_private_key(&pk_str.to_string()).unwrap(); -} - -#[test] -fn test_validate_private_key_invalid() { - let pk_str = "APrivateKey1zkp4THISISNOTAPRIVATEKEYPzCL245GyNtYJP5GYY2k22"; - - let _res = validate_private_key(&pk_str.to_string()).unwrap_err(); -} - -#[test] -fn test_validate_address() { - let add_str = "aleo1dg722m22fzpz6xjdrvl9tzu5t68zmypj5p74khlqcac0gvednygqxaax0j"; - - let _res = validate_address(&add_str.to_string()).unwrap(); -} - -#[test] -fn test_validate_address_invalid() { - let add_str = "aleo2dg722m22fzpz6xjdrvl9tzu5t68zmypj5p74khlqcac0gvednygqxaax0"; - - let _res = validate_address(&add_str.to_string()).unwrap_err(); -} - -#[test] -fn test_validate_secret_password_safe() { - //entropy should invalidate this in the future - let password = "Password123!"; - - let _res = validate_secret_password(&password.to_string()).unwrap(); -} - -#[test] -fn test_validate_secret_password_unsafe() { - let password = "password"; - - let _res = validate_secret_password(&password.to_string()).unwrap_err(); -} diff --git a/backend/src/lib.rs b/backend/src/lib.rs deleted file mode 100644 index 26878211..00000000 --- a/backend/src/lib.rs +++ /dev/null @@ -1,102 +0,0 @@ -pub mod api; -pub mod helpers; -pub mod models; -pub mod services; - -use services::account::generation::create_seed_phrase_wallet; -use services::account::generation::import_wallet; -use services::account::phrase_recovery::recover_wallet_from_seed_phrase; -use services::account::utils::{open_url, os_type}; -use services::authentication::session::get_session; -use services::local_storage::persistent_storage::{ - get_address_string, get_auth_type, get_backup_flag, get_language, get_last_sync, get_network, - get_username, update_language, -}; - -use api::user::{update_backup_flag, update_username}; -use services::local_storage::{ - encrypted_data::get_and_store_all_data, - tokens::get_stored_tokens, - utils::{ - delete_local_for_recovery, delete_util, get_private_key_tauri, get_seed_phrase, - get_view_key_tauri, - }, -}; - -// record handliong services -// use crate::services::record_handling::utils::get_all_nft_data; -use services::record_handling::{ - sync::{blocks_sync, sync_backup, txs_sync}, - transfer::{pre_install_inclusion_prover, transfer}, -}; -// wallet connect services -use crate::services::wallet_connect_api::{ - decrypt_records, get_avail_event, get_avail_events, get_balance, get_event, get_events, - get_records, get_succinct_avail_event, get_succinct_avail_events, request_create_event, sign, - verify, -}; - -#[cfg_attr(mobile, tauri::mobile_entry_point)] -pub fn run() { - tauri::Builder::default() - .plugin(tauri_plugin_deep_link::init()) - .setup(|app| { - #[cfg(desktop)] - app.handle() - .plugin(tauri_plugin_updater::Builder::new().build())?; - // NOTE: Updater is only supported on desktop platforms - - Ok(()) - }) - .invoke_handler(tauri::generate_handler![ - /* Account Management */ - create_seed_phrase_wallet, - recover_wallet_from_seed_phrase, - update_username, - import_wallet, - get_username, - delete_util, - delete_local_for_recovery, - get_private_key_tauri, - get_view_key_tauri, - get_seed_phrase, - get_and_store_all_data, - get_address_string, - get_last_sync, - get_backup_flag, - update_backup_flag, - get_network, - get_language, - update_language, - get_stored_tokens, - open_url, - os_type, - /* Authentication */ - get_session, - get_auth_type, - /* Scanning */ - txs_sync, - blocks_sync, - sync_backup, - /* Avail Services */ - get_avail_event, - get_avail_events, - // get_all_nft_data, - transfer, - /* --Wallet Connect Api */ - get_event, - get_events, - get_records, - request_create_event, - sign, - decrypt_records, - get_balance, - get_succinct_avail_event, - get_succinct_avail_events, - verify, - /* Aleo Helpers */ - pre_install_inclusion_prover - ]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} diff --git a/backend/src/main.rs b/backend/src/main.rs deleted file mode 100644 index 7f6f39eb..00000000 --- a/backend/src/main.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Prevents additional console window on Windows in release, DO NOT REMOVE!! - -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -mod api; -mod helpers; -mod models; -mod services; - -fn main() { - #[cfg(desktop)] - availx_lib::run(); -} diff --git a/backend/src/models.rs b/backend/src/models.rs deleted file mode 100644 index 7737587f..00000000 --- a/backend/src/models.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod account; -pub mod auth; -pub mod event; -pub mod event_payloads; -pub mod pointers; -pub mod storage; -pub mod transfer; -pub mod wallet; -pub mod wallet_connect; diff --git a/backend/src/models/account.rs b/backend/src/models/account.rs deleted file mode 100644 index 7ceb81f0..00000000 --- a/backend/src/models/account.rs +++ /dev/null @@ -1,24 +0,0 @@ -use serde::{ser::SerializeStruct, Deserialize, Serialize}; -use snarkvm::prelude::{Address, Network, Testnet3, ViewKey}; - -pub struct AvailKeys { - pub view_key: ViewKey, - pub address: Address, -} - -impl Serialize for AvailKeys { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("AvailKeys", 2)?; - state.serialize_field("view_key", &self.view_key.to_string())?; - state.serialize_field("address", &self.address.to_string())?; - state.end() - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct AddressRequest { - pub username: String, -} diff --git a/backend/src/models/auth.rs b/backend/src/models/auth.rs deleted file mode 100644 index 8f86abe7..00000000 --- a/backend/src/models/auth.rs +++ /dev/null @@ -1,134 +0,0 @@ -#![allow(dead_code)] -use chrono::{DateTime, Utc}; -use openssl::base64; -use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer}; - -use avail_common::models::server_auth::{CreateSessionResponse, VerifySessionRequest}; -use uuid::Uuid; - -#[allow(non_snake_case)] -pub struct Options { - pub service: String, - pub title: String, - pub subtitle: String, - pub description: String, - pub cancel: String, - pub accessible: String, - pub accessControl: Option, - pub storage: Option, - pub securityLevel: String, - pub authenticationType: Option, -} -#[allow(non_snake_case)] -impl Options { - pub fn new( - service: String, - title: String, - subtitle: String, - description: String, - cancel: String, - accessible: String, - accessControl: Option, - storage: Option, - securityLevel: String, - authenticationType: Option, - ) -> Options { - Options { - service, - title, - subtitle, - description, - cancel, - accessible, - accessControl, - storage, - securityLevel, - authenticationType, - } - } - - pub fn default() -> Options { - Options { - service: String::from("com.avail"), - title: String::from("Authentication"), - subtitle: String::from("Login to your wallet"), - cancel: String::from("Cancel"), - description: String::from(""), - accessible: String::from("AccessibleWhenUnlockedThisDeviceOnly"), - accessControl: None, - storage: None, - securityLevel: String::from("ANY"), - authenticationType: None, - } - } -} - -pub struct PbkdfResult { - pub salt: [u8; 16], - pub hash: String, -} - -impl Serialize for PbkdfResult { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let salt = base64::encode_block(&self.salt); - let hash = &self.hash; - let mut state = serializer.serialize_struct("PbkdfResult", 2)?; - state.serialize_field("salt", &salt)?; - state.serialize_field("hash", &hash)?; - state.end() - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct VerifySessionResponse { - pub signature: String, - pub session_id: String, -} - -impl VerifySessionResponse { - pub fn to_request(&self) -> VerifySessionRequest { - VerifySessionRequest { - signature: self.signature.to_string(), - session_id: Uuid::parse_str(&self.session_id).unwrap(), - } - } -} - -impl From for VerifySessionResponse { - fn from(request: VerifySessionRequest) -> Self { - VerifySessionResponse { - signature: request.signature, - session_id: request.session_id.to_string(), - } - } -} - -#[derive(Serialize, Deserialize)] -pub struct CreateSessionRequest { - pub hash: String, - pub session_id: String, - pub expires_on: DateTime, -} - -impl CreateSessionRequest { - pub fn to_response(&self) -> CreateSessionResponse { - CreateSessionResponse { - hash: self.hash.to_string(), - session_id: Uuid::parse_str(&self.session_id).unwrap(), - expires_on: self.expires_on, - } - } -} - -impl From for CreateSessionRequest { - fn from(response: CreateSessionResponse) -> Self { - CreateSessionRequest { - hash: response.hash, - session_id: response.session_id.to_string(), - expires_on: response.expires_on, - } - } -} diff --git a/backend/src/models/event.rs b/backend/src/models/event.rs deleted file mode 100644 index dd74d40d..00000000 --- a/backend/src/models/event.rs +++ /dev/null @@ -1,346 +0,0 @@ -use avail_common::models::encrypted_data::{EventStatus, EventTypeCommon, TransactionState}; -use chrono::{DateTime, Local}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -pub struct Event { - _id: String, - #[serde(rename = "type")] - event_type: EventTypeCommon, - owner: String, - status: EventStatus, - created: DateTime, - broadcast: Option>, // finalized - #[serde(rename = "broadcastHeight")] - broadcast_height: Option, // finalized height - settled: Option>, // i.e confirmed - network: Network, - #[serde(rename = "transactionId")] - transaction_id: Option, - #[serde(rename = "programId")] - program_id: Option, - #[serde(rename = "functionId")] - function_id: Option, - inputs: Vec, - transitions: Vec, - fee_transition: Option, - height: Option, - description: Option, - fee: Option, - visibility: Visibility, // public or private - error: Option, -} - -impl Event { - pub fn new( - _id: String, - event_type: EventTypeCommon, - owner: String, - status: EventStatus, - created: DateTime, - broadcast: Option>, - broadcast_height: Option, - settled: Option>, - network: Network, - transaction_id: Option, - program_id: Option, - function_id: Option, - inputs: Vec, - transitions: Vec, - fee_transition: Option, - height: Option, - description: Option, - fee: Option, - visibility: Visibility, - error: Option, - ) -> Self { - Self { - _id, - event_type, - owner, - status, - created, - broadcast, - broadcast_height, - settled, - network, - transaction_id, - program_id, - function_id, - inputs, - transitions, - fee_transition, - height, - description, - fee, - visibility, - error, - } - } - - pub fn to_avail_event(&self) -> AvailEvent { - AvailEvent::new( - self._id.clone(), - self.event_type.clone(), - self.owner.clone(), - self.status.clone().to_transaction_state(), - self.created.clone(), - self.broadcast.clone(), - self.broadcast_height.clone(), - self.settled.clone(), - self.network.clone(), - self.transaction_id.clone(), - self.program_id.clone(), - self.function_id.clone(), - self.inputs.clone(), - self.transitions.clone(), - self.fee_transition.clone(), - self.height.clone(), - self.description.clone(), - self.fee.clone(), - self.visibility.clone(), - self.error.clone(), - None, - None, - None, - None, - ) - } - - pub fn get_created(&self) -> DateTime { - self.created - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -pub struct EventTransition { - #[serde(rename = "transitionId")] - transition_id: String, - #[serde(rename = "programId")] - program_id: String, - #[serde(rename = "functionId")] - function_id: String, - inputs: Vec, - outputs: Vec, -} - -impl EventTransition { - pub fn new( - transition_id: String, - program_id: String, - function_id: String, - inputs: Vec, - outputs: Vec, - ) -> Self { - Self { - transition_id, - program_id, - function_id, - inputs, - outputs, - } - } - - pub fn program_id(&self) -> &String { - &self.program_id - } - - pub fn function_id(&self) -> &String { - &self.function_id - } - - pub fn inputs(&self) -> Vec { - self.inputs.clone() - } -} - -/// Internal avail event used to display transaction history in a list -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -pub struct SuccinctAvailEvent { - id: String, - to: Option, - from: Option, - amount: Option, - fee: Option, - message: Option, - #[serde(rename = "type")] - event_type: EventTypeCommon, - status: TransactionState, - created: DateTime, - #[serde(rename = "programId")] - program_id: Option, - #[serde(rename = "functionId")] - function_id: Option, -} - -impl SuccinctAvailEvent { - pub fn new( - id: String, - to: Option, - from: Option, - amount: Option, - fee: Option, - message: Option, - event_type: EventTypeCommon, - status: TransactionState, - created: DateTime, - program_id: Option, - function_id: Option, - ) -> Self { - Self { - id, - to, - from, - amount, - fee, - message, - event_type, - status, - created, - program_id, - function_id, - } - } - - pub fn get_created(&self) -> DateTime { - self.created - } -} - -/// Internal avail event used to display a full event -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -pub struct AvailEvent { - _id: String, - #[serde(rename = "type")] - event_type: EventTypeCommon, - owner: String, - status: TransactionState, - created: DateTime, - broadcast: Option>, // finalized - #[serde(rename = "broadcastHeight")] - broadcast_height: Option, // finalized height - settled: Option>, // i.e confirmed - network: Network, - #[serde(rename = "transactionId")] - transaction_id: Option, - #[serde(rename = "programId")] - program_id: Option, - #[serde(rename = "functionId")] - function_id: Option, - inputs: Vec, - transitions: Vec, - fee_transition: Option, - height: Option, - description: Option, - fee: Option, - visibility: Visibility, // public or private - error: Option, - message: Option, - to: Option, - from: Option, - amount: Option, -} - -impl AvailEvent { - pub fn new( - _id: String, - event_type: EventTypeCommon, - owner: String, - status: TransactionState, - created: DateTime, - broadcast: Option>, - broadcast_height: Option, - settled: Option>, - network: Network, - transaction_id: Option, - program_id: Option, - function_id: Option, - inputs: Vec, - transitions: Vec, - fee_transition: Option, - height: Option, - description: Option, - fee: Option, - visibility: Visibility, - error: Option, - message: Option, - to: Option, - from: Option, - amount: Option, - ) -> Self { - Self { - _id, - event_type, - owner, - status, - created, - broadcast, - broadcast_height, - settled, - network, - transaction_id, - program_id, - function_id, - inputs, - transitions, - fee_transition, - height, - description, - fee, - visibility, - error, - message, - to, - from, - amount, - } - } - - pub fn get_created(&self) -> DateTime { - self.created - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -pub enum Network { - AleoTestnet, - AleoDevnet, - AleoMainnet, -} - -impl Network { - pub fn to_string(&self) -> String { - match self { - Network::AleoTestnet => "testnet3".to_string(), - Network::AleoDevnet => "devnet".to_string(), - Network::AleoMainnet => "mainnet".to_string(), - } - } - - pub fn from_str(s: &str) -> Option { - match s { - "testnet3" => Some(Network::AleoTestnet), - "devnet" => Some(Network::AleoDevnet), - "mainnet" => Some(Network::AleoMainnet), - _ => None, - } - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -pub enum Visibility { - Private, - Public, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TxScanResponse { - pub txs: bool, - pub block_height: u32, -} - -impl TxScanResponse { - pub fn new(txs: bool, block_height: u32) -> Self { - Self { txs, block_height } - } -} diff --git a/backend/src/models/event_payloads.rs b/backend/src/models/event_payloads.rs deleted file mode 100644 index 19993add..00000000 --- a/backend/src/models/event_payloads.rs +++ /dev/null @@ -1,10 +0,0 @@ -use serde::Serialize; - -#[derive(Serialize, Clone)] -pub struct ScanProgressPayload { - pub progress: f32, -} - -// TODO : Transaction execution event -// TODO : Transaction confirmed event -// TODO : Transaction failed event diff --git a/backend/src/models/pointers.rs b/backend/src/models/pointers.rs deleted file mode 100644 index 4b30c748..00000000 --- a/backend/src/models/pointers.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod deployment; -pub mod message; -pub mod record; -pub mod transaction; -pub mod transition; diff --git a/backend/src/models/pointers/deployment.rs b/backend/src/models/pointers/deployment.rs deleted file mode 100644 index 43de76e1..00000000 --- a/backend/src/models/pointers/deployment.rs +++ /dev/null @@ -1,377 +0,0 @@ -use snarkvm::prelude::{Address, Network}; - -use chrono::{DateTime, Local}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -use crate::models::event::{ - AvailEvent, Event, Network as EventNetwork, SuccinctAvailEvent, Visibility, -}; -use crate::services::local_storage::{ - encrypted_data::store_encrypted_data, - persistent_storage::{get_address, get_address_string, get_network}, - session::view::VIEWSESSION, -}; -use crate::services::record_handling::utils::get_fee_transition; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::{ - encrypted_data::{ - EncryptedData, EncryptedDataRecord, EncryptedDataTypeCommon, EventTypeCommon, - TransactionState, - }, - traits::encryptable::{Encryptable, EncryptedStruct}, - }, -}; - -/// Deployment pointers are used to keep track of leo program deployment history -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct DeploymentPointer { - pub id: Option, - pub program_id: String, - pub fee: f64, - pub state: TransactionState, - pub block_height: Option, - pub spent_fee_nonce: Option, - pub created: DateTime, - pub finalized: Option>, - pub error: Option, -} - -fn decrypt(encrypted_struct: EncryptedStruct) -> AvailResult> { - let view_key = VIEWSESSION.get_instance::()?; - let transition: DeploymentPointer = encrypted_struct.decrypt(view_key)?; - - Ok(transition) -} - -impl DeploymentPointer { - pub fn decrypt_x(encrypted_struct: EncryptedStruct) -> AvailResult> { - let view_key = VIEWSESSION.get_instance::()?; - let transition: DeploymentPointer = encrypted_struct.decrypt(view_key)?; - - Ok(transition) - } - - pub fn new( - id: Option, - program_id: String, - fee: f64, - state: TransactionState, - block_height: Option, - spent_fee_nonce: Option, - created: DateTime, - finalized: Option>, - error: Option, - ) -> Self { - Self { - id, - program_id, - fee, - state, - block_height, - spent_fee_nonce, - created, - finalized, - error, - } - } - - pub fn encrypt_and_store(&self, address: Address) -> AvailResult { - let encrypted_transaction = self.to_encrypted_data(address)?; - let id = match encrypted_transaction.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - store_encrypted_data(encrypted_transaction)?; - Ok(id) - } - - pub fn update_confirmed_deployment( - &mut self, - transaction_id: N::TransactionID, - block_height: u32, - fee: Option, - ) { - self.id = Some(transaction_id); - self.state = TransactionState::Confirmed; - self.block_height = Some(block_height); - self.finalized = Some(chrono::Local::now()); - self.fee = fee.unwrap_or(self.fee); - } - - pub fn update_pending_deployment(&mut self) { - self.state = TransactionState::Pending; - } - - pub fn update_failed_deployment(&mut self, error: String) { - self.state = TransactionState::Failed; - self.error = Some(error); - } - - pub fn update_rejected_deployment( - &mut self, - error: String, - transaction_id: Option, - block_height: u32, - fee: Option, - ) { - self.state = TransactionState::Rejected; - self.error = Some(error); - self.finalized = Some(chrono::Local::now()); - self.id = transaction_id; - self.block_height = Some(block_height); - self.fee = fee.unwrap_or(self.fee); - } - - pub fn update_aborted_deployment( - &mut self, - error: String, - transaction_id: N::TransactionID, - block_height: u32, - ) { - self.state = TransactionState::Aborted; - self.error = Some(error); - self.finalized = Some(chrono::Local::now()); - self.id = Some(transaction_id); - self.block_height = Some(block_height); - } - - pub fn update_cancelled_deployment(&mut self) { - self.state = TransactionState::Cancelled; - } - - pub fn to_encrypted_data_from_record( - encrypted_data_record: EncryptedDataRecord, - ) -> AvailResult { - let address = get_address::()?; - let encrypted_struct = encrypted_data_record.to_enrypted_struct::()?; - let record = decrypt::(encrypted_struct)?; - let encrypted_data = record.to_encrypted_data(address)?; - Ok(encrypted_data) - } - - pub fn to_encrypted_data(&self, encrypt_for: Address) -> AvailResult { - let encrypted_record_pointer = self.encrypt_for(encrypt_for)?; - - let network = get_network()?; - let id = Uuid::new_v4(); - let flavour = EncryptedDataTypeCommon::Deployment; - let created_at = chrono::Utc::now(); - - let encrypted_data = EncryptedData::new( - Some(id), - encrypt_for.to_string(), - encrypted_record_pointer.cipher_text.to_string(), - encrypted_record_pointer.nonce.to_string(), - flavour, - None, - Some(self.program_id.clone()), - None, - created_at, - None, - None, - network, - None, - None, - Some(EventTypeCommon::Deploy), - None, - Some(self.state.clone()), - ); - - Ok(encrypted_data) - } - - pub fn to_event(&self, id: &str) -> AvailResult { - let address = get_address_string()?; - let network = get_network()?; - let event_network = match EventNetwork::from_str(&network) { - Some(network) => network, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Network not found".to_string(), - "Network not found".to_string(), - )) - } - }; - - let tx_id = match &self.id { - Some(id) => Some(id.to_string()), - None => None, - }; - - let fee_transition = match &self.id { - Some(id) => match get_fee_transition::(*id) { - Ok(fee_transition) => Some(fee_transition), - Err(e) => return Err(e), - }, - None => None, - }; - - let event = Event::new( - id.to_string(), - EventTypeCommon::Deploy, - address, - self.state.to_event_status(), - self.created, - None, - None, - self.finalized, - event_network, - tx_id, - Some(self.program_id.clone()), - None, - vec![], - vec![], - fee_transition, - self.block_height, - None, - Some(self.fee), - Visibility::Public, - self.error.clone(), - ); - - Ok(event) - } - - pub fn to_avail_event(&self, id: &str) -> AvailResult { - let address = get_address_string()?; - let network = get_network()?; - let event_network = match EventNetwork::from_str(&network) { - Some(network) => network, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Network not found".to_string(), - "Network not found".to_string(), - )) - } - }; - - let tx_id = match &self.id { - Some(id) => Some(id.to_string()), - None => None, - }; - - let fee_transition = match &self.id { - Some(id) => match get_fee_transition::(*id) { - Ok(fee_transition) => Some(fee_transition), - Err(e) => return Err(e), - }, - None => None, - }; - - let event = AvailEvent::new( - id.to_string(), - EventTypeCommon::Deploy, - address, - self.state.clone(), - self.created, - None, - None, - self.finalized, - event_network, - tx_id, - Some(self.program_id.clone()), - None, - vec![], - vec![], - fee_transition, - self.block_height, - None, - Some(self.fee), - Visibility::Public, - self.error.clone(), - None, - None, - None, - None, - ); - - Ok(event) - } - - pub fn to_succinct_avail_event(&self, id: &str) -> AvailResult { - let event = SuccinctAvailEvent::new( - id.to_string(), - None, - None, - None, - Some(self.fee), - None, - EventTypeCommon::Deploy, - self.state.clone(), - self.created, - Some(self.program_id.clone()), - None, - ); - - Ok(event) - } - - pub fn decrypt_to_event(encrypted_transition: EncryptedData) -> AvailResult { - let v_key = VIEWSESSION.get_instance::()?; - - let db_id = match encrypted_transition.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - let encrypted_data = encrypted_transition.to_enrypted_struct::()?; - - let transition: DeploymentPointer = encrypted_data.decrypt(v_key)?; - - transition.to_event(&db_id) - } - - pub fn decrypt_to_avail_event(encrypted_deployment: EncryptedData) -> AvailResult { - let v_key = VIEWSESSION.get_instance::()?; - - let db_id = match encrypted_deployment.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - let encrypted_data = encrypted_deployment.to_enrypted_struct::()?; - - let deployment: DeploymentPointer = encrypted_data.decrypt(v_key)?; - - deployment.to_avail_event(&db_id) - } - - pub fn decrypt_to_succinct_avail_event( - encrypted_deployment: EncryptedData, - ) -> AvailResult { - let v_key = VIEWSESSION.get_instance::()?; - - let db_id = match encrypted_deployment.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - let encrypted_data = encrypted_deployment.to_enrypted_struct::()?; - - let deployment: DeploymentPointer = encrypted_data.decrypt(v_key)?; - - deployment.to_succinct_avail_event(&db_id) - } -} diff --git a/backend/src/models/pointers/message.rs b/backend/src/models/pointers/message.rs deleted file mode 100644 index 5cbb6560..00000000 --- a/backend/src/models/pointers/message.rs +++ /dev/null @@ -1,115 +0,0 @@ -use chrono::{DateTime, Local}; -use serde::{Deserialize, Serialize}; -use snarkvm::prelude::{confirmed::ConfirmedTransaction, Address, Network}; -use uuid::Uuid; - -use crate::helpers::utils::get_timestamp_from_i64; -use crate::services::local_storage::{ - persistent_storage::get_network, storage_api::transaction::get_transaction_ids, -}; -use avail_common::{ - aleo_tools::api::AleoAPIClient, - errors::AvailResult, - models::{ - encrypted_data::{EncryptedData, EncryptedDataTypeCommon}, - traits::encryptable::Encryptable, - }, -}; - -use crate::api::aleo_client::setup_client; - -/// Encrypted and sent to the address the wallet owner interacted with in the transaction to avoid scanning times -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct TransactionMessage { - id: N::TransactionID, - confirmed_height: u32, - from: String, - message: Option, -} - -impl TransactionMessage { - pub fn new( - id: N::TransactionID, - confirmed_height: u32, - from: String, - message: Option, - ) -> Self { - Self { - id, - confirmed_height, - from, - message, - } - } - - pub fn id(&self) -> N::TransactionID { - self.id - } - - pub fn confirmed_height(&self) -> u32 { - self.confirmed_height - } - - pub fn from(&self) -> String { - self.from.to_owned() - } - - pub fn message(&self) -> Option { - self.message.to_owned() - } - - pub fn to_encrypted_data(&self, encrypt_for: Address) -> AvailResult { - let encrypted_tx_message = self.encrypt_for(encrypt_for)?; - let network = get_network()?; - - let _id = Uuid::new_v4(); - let flavour = EncryptedDataTypeCommon::TransactionMessage; - let created_at = chrono::Utc::now(); - - let encrypted_data = EncryptedData::new( - None, - encrypt_for.to_string(), - encrypted_tx_message.cipher_text.to_string(), - encrypted_tx_message.nonce.to_string(), - flavour, - None, - None, - None, - created_at, - None, - None, - network, - None, - None, - None, - None, - None, - ); - - Ok(encrypted_data) - } - - /// Checks if the transaction has been stored before and checks if the transaction is found at the confirmed block height - pub fn verify(&self) -> AvailResult<(Option>, DateTime)> { - let api_client = setup_client::()?; - - let block = api_client.get_block(self.confirmed_height)?; - let timestamp = get_timestamp_from_i64(block.timestamp())?; - - let stored_transaction_ids = get_transaction_ids::()?; - if stored_transaction_ids.contains(&self.id) { - return Ok((None, timestamp)); - } - - let tx_check = block.transactions().get(&self.id); - - match tx_check { - Some(tx) => { - return Ok((Some(tx.to_owned()), timestamp)); - } - None => { - return Ok((None, timestamp)); - } - } - } -} diff --git a/backend/src/models/pointers/record.rs b/backend/src/models/pointers/record.rs deleted file mode 100644 index 9334fd45..00000000 --- a/backend/src/models/pointers/record.rs +++ /dev/null @@ -1,255 +0,0 @@ -use std::collections::HashMap; - -use serde::{Deserialize, Serialize}; -use snarkvm::prelude::{Address, Field, FromStr, Network, Plaintext, Record}; -use uuid::Uuid; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::{ - encrypted_data::{ - EncryptedData, EncryptedDataRecord, EncryptedDataTypeCommon, RecordTypeCommon, - }, - traits::encryptable::{Encryptable, EncryptedStruct}, - }, -}; - -use crate::api::aleo_client::setup_client; - -use crate::services::{ - local_storage::{ - persistent_storage::{get_address, get_network}, - session::view::VIEWSESSION, - }, - record_handling::utils::transition_to_record, -}; - -/// The record struct represents a pointer to a single record on the Aleo blockchain owned by the wallet account. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[serde(bound = "N: Network")] -pub struct AvailRecord { - pub pointer: Pointer, - pub metadata: Metadata, -} - -fn decrypt(encrypted_struct: EncryptedStruct) -> AvailResult> { - let view_key = VIEWSESSION.get_instance::()?; - let record: AvailRecord = encrypted_struct.decrypt(view_key)?; - Ok(record) -} - -impl AvailRecord { - pub fn new(pointer: Pointer, metadata: Metadata) -> Self { - Self { pointer, metadata } - } - - pub fn to_encrypted_data_from_record( - encrypted_data_record: EncryptedDataRecord, - ) -> AvailResult { - let address = get_address::()?; - let encrypted_struct = encrypted_data_record.to_enrypted_struct::()?; - let record = decrypt::(encrypted_struct)?; - let encrypted_data = record.to_encrypted_data(address)?; - Ok(encrypted_data) - } - - pub fn to_encrypted_data(&self, encrypt_for: Address) -> AvailResult { - let encrypted_record_pointer = self.encrypt_for(encrypt_for)?; - let network = get_network()?; - - let id = Uuid::new_v4(); - let flavour = EncryptedDataTypeCommon::Record; - let created_at = chrono::Utc::now(); - - let encrypted_data = EncryptedData::new( - Some(id), - encrypt_for.to_string(), - encrypted_record_pointer.cipher_text.to_string(), - encrypted_record_pointer.nonce.to_string(), - flavour, - Some(self.metadata.record_type.clone()), - Some(self.metadata.program_id.clone()), - Some(self.metadata.function_id.clone()), - created_at, - None, - None, - network, - Some(self.metadata.name.clone()), - Some(self.metadata.spent), - None, - Some(self.metadata.nonce.clone()), - None, - ); - - Ok(encrypted_data) - } - - pub fn from_record( - commitment: Field, - record: &Record>, - sk_tag: Field, - record_type: RecordTypeCommon, - program_id: &str, - block_height: u32, - transaction_id: N::TransactionID, - transition_id: N::TransitionID, - function_id: &str, - name: String, - index: u8, - owner: &str, - ) -> AvailResult { - let tag = - match Record::>::tag(sk_tag, commitment) { - Ok(tag) => tag, - Err(e) => return Err(AvailError::new( - AvailErrorType::InvalidData, - "Error computing the record tag from sk_tag and commitment using record::tag()" - .to_string() - + &e.to_string(), - "Error forming record pointer, scan will restart at this height.".to_string(), - )), - }; - - let pointer = Pointer::new( - block_height, - transaction_id, - transition_id, - &commitment.to_string(), - &tag.to_string(), - index, - owner, - ); - - //TODO: V2-update to RecordTypeCommon::Tokens and have a token identification system (in progress) - let metadata = Metadata::new( - record_type, - program_id.to_string(), - function_id.to_string(), - false, - name, - record.nonce().to_string(), - ); - - Ok(Self::new(pointer, metadata)) - } - - pub fn to_record(&self) -> AvailResult>> { - let api_client = setup_client::()?; - - let record_transaction = api_client.get_transaction(self.pointer.transaction_id)?; - - let transition = match record_transaction.find_transition(&self.pointer.transition_id) { - Some(transition) => transition, - None => { - return Err(AvailError::new( - AvailErrorType::NotFound, - "Transition not found".to_string(), - "Transition not found".to_string(), - )) - } - }; - - let (record_plaintext, _record_ciphertext, _data) = - transition_to_record(transition, &self.pointer.commitment, self.pointer.index)?; - - Ok(record_plaintext) - } - - pub fn to_record_texts_and_data( - &self, - ) -> AvailResult<(String, String, HashMap)> { - let api_client = setup_client::()?; - - let record_transaction = api_client.get_transaction(self.pointer.transaction_id)?; - - let transition = match record_transaction.find_transition(&self.pointer.transition_id) { - Some(transition) => transition, - None => { - return Err(AvailError::new( - AvailErrorType::NotFound, - "Transition not found".to_string(), - "Transition not found".to_string(), - )) - } - }; - - let (record_plaintext, record_ciphertext, data) = - transition_to_record(transition, &self.pointer.commitment, self.pointer.index)?; - Ok(( - record_plaintext.to_string(), - record_ciphertext.to_string(), - data, - )) - } - - pub fn is_spent(&self) -> AvailResult { - Ok(self.metadata.spent) - } - - pub fn tag(&self) -> AvailResult> { - Ok(Field::::from_str(&self.pointer.tag)?) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct Pointer { - pub block_height: u32, - pub transaction_id: N::TransactionID, - pub transition_id: N::TransitionID, - pub commitment: String, - pub tag: String, - pub index: u8, - pub owner: String, -} - -impl Pointer { - pub fn new( - block_height: u32, - transaction_id: N::TransactionID, - transition_id: N::TransitionID, - commitment: &str, - tag: &str, - index: u8, - owner: &str, - ) -> Self { - Self { - block_height, - transaction_id, - transition_id, - commitment: commitment.to_string(), - tag: tag.to_string(), - index, - owner: owner.to_string(), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct Metadata { - pub record_type: RecordTypeCommon, - pub program_id: String, - pub function_id: String, - pub spent: bool, - pub name: String, - pub nonce: String, -} - -impl Metadata { - pub fn new( - record_type: RecordTypeCommon, - program_id: String, - function_id: String, - spent: bool, - name: String, - nonce: String, - ) -> Self { - Self { - record_type, - program_id, - function_id, - spent, - name, - nonce, - } - } -} diff --git a/backend/src/models/pointers/transaction.rs b/backend/src/models/pointers/transaction.rs deleted file mode 100644 index 595dd704..00000000 --- a/backend/src/models/pointers/transaction.rs +++ /dev/null @@ -1,660 +0,0 @@ -use snarkvm::prelude::*; - -use chrono::{DateTime, Local}; -use serde::{Deserialize, Serialize}; -use std::fmt::{Display, Formatter, Result as Res}; -use uuid::Uuid; - -use crate::models::event::{ - AvailEvent, Event, EventTransition, Network as EventNetwork, SuccinctAvailEvent, Visibility, -}; - -use crate::{ - api::aleo_client::setup_client, - services::local_storage::{ - encrypted_data::store_encrypted_data, - persistent_storage::{get_address, get_address_string, get_network}, - session::view::VIEWSESSION, - }, - services::record_handling::{decrypt_transition::DecryptTransition, utils::get_fee_transition}, -}; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::{ - encrypted_data::{ - EncryptedData, EncryptedDataRecord, EncryptedDataTypeCommon, EventTypeCommon, - TransactionState, - }, - traits::encryptable::{Encryptable, EncryptedStruct}, - }, -}; - -/// Pointer to a transaction that has been executed by the wallet owner -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -#[serde(bound = "N: Network")] -pub struct TransactionPointer { - to: Option, - transaction_id: Option, - state: TransactionState, - block_height: Option, - executed_program_id: Option, - executed_function_id: Option, - transitions: Vec>, - spent_record_pointers_nonces: Vec, - created: DateTime, - finalized: Option>, - message: Option, - event_type: EventTypeCommon, - amount: Option, - fee: Option, - error: Option, -} - -fn decrypt(encrypted_struct: EncryptedStruct) -> AvailResult> { - let view_key = VIEWSESSION.get_instance::()?; - let transition: TransactionPointer = encrypted_struct.decrypt(view_key)?; - - Ok(transition) -} - -impl TransactionPointer { - #[allow(dead_code)] - pub fn new( - to: Option, - transaction_id: Option, - state: TransactionState, - block_height: Option, - executed_program_id: Option, - executed_function_id: Option, - transitions: Vec>, - spent_record_pointers_nonces: Vec, - created: DateTime, - finalized: Option>, - message: Option, - event_type: EventTypeCommon, - amount: Option, - fee: Option, - error: Option, - ) -> Self { - Self { - to, - transaction_id, - state, - block_height, - executed_program_id, - executed_function_id, - transitions, - spent_record_pointers_nonces, - created, - finalized, - message, - event_type, - amount, - fee, - error, - } - } - - #[allow(dead_code)] - pub fn to(&self) -> Option { - self.to.clone() - } - - pub fn transaction_id(&self) -> Option { - self.transaction_id - } - - #[allow(dead_code)] - pub fn state(&self) -> TransactionState { - self.state.clone() - } - - #[allow(dead_code)] - pub fn block_height(&self) -> Option { - self.block_height - } - - #[allow(dead_code)] - pub fn executed_program_id(&self) -> Option { - self.executed_program_id.clone() - } - - #[allow(dead_code)] - pub fn executed_function_id(&self) -> Option { - self.executed_function_id.clone() - } - - #[allow(dead_code)] - pub fn transitions(&self) -> Vec> { - self.transitions.clone() - } - - #[allow(dead_code)] - pub fn spent_record_pointers_nonces(&self) -> Vec { - self.spent_record_pointers_nonces.clone() - } - - pub fn created(&self) -> DateTime { - self.created - } - - pub fn finalized(&self) -> Option> { - self.finalized - } - - pub fn message(&self) -> Option { - self.message.clone() - } - - pub fn event_type(&self) -> EventTypeCommon { - self.event_type.clone() - } - - pub fn amount(&self) -> Option { - self.amount - } - - pub fn fee(&self) -> Option { - self.fee - } - - pub fn update_state(&mut self, state: TransactionState) { - self.state = state; - } - - pub fn error(&self) -> Option { - self.error.clone() - } - - pub fn update_confirmed_transaction( - &mut self, - transaction_id: N::TransactionID, - block_height: u32, - transitions: Vec>, - finalized: DateTime, - state: TransactionState, - fee: Option, - ) { - self.transaction_id = Some(transaction_id); - self.block_height = Some(block_height); - self.transitions = transitions; - self.finalized = Some(finalized); - self.state = state; - self.fee = fee; - } - - pub fn update_pending_transaction(&mut self) { - self.state = TransactionState::Pending; - } - - pub fn update_failed_transaction(&mut self, error: String) { - self.state = TransactionState::Failed; - self.error = Some(error); - self.fee = None; - } - - pub fn update_rejected_transaction( - &mut self, - error: String, - transaction_id: Option, - block_height: u32, - fee: Option, - ) { - self.state = TransactionState::Rejected; - self.error = Some(error); - self.finalized = Some(chrono::Local::now()); - self.transaction_id = transaction_id; - self.block_height = Some(block_height); - self.fee = fee; - } - - pub fn update_aborted_transaction( - &mut self, - error: String, - transaction_id: N::TransactionID, - block_height: u32, - ) { - self.state = TransactionState::Aborted; - self.error = Some(error); - self.finalized = Some(chrono::Local::now()); - self.transaction_id = Some(transaction_id); - self.block_height = Some(block_height); - self.fee = None; - } - - pub fn update_cancelled_transaction(&mut self) { - self.state = TransactionState::Cancelled; - } - - pub fn to_encrypted_data_from_record( - encrypted_data_record: EncryptedDataRecord, - ) -> AvailResult { - let address = get_address::()?; - let encrypted_struct = encrypted_data_record.to_enrypted_struct::()?; - let record = decrypt::(encrypted_struct)?; - let encrypted_data = record.to_encrypted_data(address)?; - Ok(encrypted_data) - } - - pub fn to_encrypted_data(&self, encrypt_for: Address) -> AvailResult { - let network = get_network()?; - let encrypted_tx = self.encrypt_for(encrypt_for)?; - - let id = Uuid::new_v4(); - let flavour = EncryptedDataTypeCommon::Transaction; - let created_at = chrono::Utc::now(); - - let program_ids = self - .transitions - .iter() - .map(|x| x.program_id.clone()) - .collect::>(); - let function_ids = self - .transitions - .iter() - .map(|x| x.function_id.clone()) - .collect::>(); - let json_program_ids = serde_json::to_string(&program_ids)?; - let json_function_ids = serde_json::to_string(&function_ids)?; - - let encrypted_data = EncryptedData::new( - Some(id), - encrypt_for.to_string(), - encrypted_tx.cipher_text.to_string(), - encrypted_tx.nonce.to_string(), - flavour, - None, - Some(json_program_ids), - Some(json_function_ids), - created_at, - None, - None, - network, - None, - None, - Some(self.event_type.clone()), - None, - Some(self.state.clone()), - ); - - Ok(encrypted_data) - } - - pub fn encrypt_and_store(&self, address: Address) -> AvailResult { - let encrypted_transaction = self.to_encrypted_data(address)?; - let id = match encrypted_transaction.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - store_encrypted_data(encrypted_transaction)?; - Ok(id) - } - - pub fn to_event(&self, id: &str) -> AvailResult { - let address = get_address_string()?; - let network = get_network()?; - - let event_network = match EventNetwork::from_str(&network) { - Some(network) => network, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Network not found".to_string(), - "Network not found".to_string(), - )) - } - }; - - let v_key = VIEWSESSION.get_instance::()?; - - let api_client = setup_client::()?; - - let event_transaction = match self.transaction_id { - Some(id) => match api_client.get_transaction(id) { - Ok(tx) => Some(tx), - Err(_) => { - return Err(AvailError::new( - AvailErrorType::Node, - "Transaction not found".to_string(), - "Transaction not found".to_string(), - )) - } - }, - None => None, - }; - - let transitions = match event_transaction { - Some(event_transaction) => match self - .transitions - .iter() - .map(|x| x.to_event_transition(v_key, &event_transaction)) - .collect::>>() - { - Ok(event_transitions) => event_transitions, - Err(e) => return Err(e), - }, - None => vec![], - }; - - let fee_transition = match self.transaction_id { - Some(id) => match get_fee_transition::(id) { - Ok(fee_transition) => Some(fee_transition), - Err(e) => return Err(e), - }, - None => None, - }; - - let tx_id_str = match self.transaction_id { - Some(id) => Some(id.to_string()), - None => None, - }; - - let root_inputs = match &self.executed_function_id { - Some(function_id) => { - match &self.executed_program_id { - Some(program_id) => { - // check if program id and function id match an event_transition and fetch the inputs as root_inputs - match transitions.iter().find(|x| { - x.program_id() == program_id && x.function_id() == function_id - }) { - Some(event_transition) => event_transition.inputs().clone(), - None => vec![], - } - } - None => vec![], - } - } - None => vec![], - }; - - let event = Event::new( - id.to_string(), - self.event_type.clone(), - address, - self.state.to_event_status(), - self.created, - None, - None, - self.finalized, - event_network, - tx_id_str, - self.executed_program_id.clone(), - self.executed_function_id.clone(), - root_inputs, - transitions, - fee_transition, - self.block_height, - None, - self.fee.clone(), - // TODO - Deduce visibility from transaction - Visibility::Private, - self.error.clone(), - ); - - Ok(event) - } - - pub fn to_avail_event(&self, id: &str) -> AvailResult { - let address = get_address_string()?; - let network = get_network()?; - - let event_network = match EventNetwork::from_str(&network) { - Some(network) => network, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Network not found".to_string(), - "Network not found".to_string(), - )) - } - }; - - let v_key = VIEWSESSION.get_instance::()?; - - let api_client = setup_client::()?; - - let event_transaction = match self.transaction_id { - Some(id) => match api_client.get_transaction(id) { - Ok(tx) => Some(tx), - Err(_) => { - return Err(AvailError::new( - AvailErrorType::Node, - "Transaction not found".to_string(), - "Transaction not found".to_string(), - )) - } - }, - None => None, - }; - - let transitions = match event_transaction { - Some(event_transaction) => match self - .transitions - .iter() - .map(|x| x.to_event_transition(v_key, &event_transaction)) - .collect::>>() - { - Ok(event_transitions) => event_transitions, - Err(e) => return Err(e), - }, - None => vec![], - }; - - let fee_transition = match self.transaction_id { - Some(id) => match get_fee_transition::(id) { - Ok(fee_transition) => Some(fee_transition), - Err(e) => return Err(e), - }, - None => None, - }; - - let tx_id_str = match self.transaction_id { - Some(id) => Some(id.to_string()), - None => None, - }; - - let root_inputs = match &self.executed_function_id { - Some(function_id) => { - match &self.executed_program_id { - Some(program_id) => { - // check if program id and function id match an event_transition and fetch the inputs as root_inputs - match transitions.iter().find(|x| { - x.program_id() == program_id && x.function_id() == function_id - }) { - Some(event_transition) => event_transition.inputs().clone(), - None => vec![], - } - } - None => vec![], - } - } - None => vec![], - }; - - let event = AvailEvent::new( - id.to_string(), - self.event_type.clone(), - address, - self.state.clone(), - self.created, - None, - None, - self.finalized, - event_network, - tx_id_str, - self.executed_program_id.clone(), - self.executed_function_id.clone(), - root_inputs, - transitions, - fee_transition, - self.block_height, - None, - self.fee.clone(), - Visibility::Private, - self.error.clone(), - self.message.clone(), - self.to.clone(), - None, - self.amount.clone(), - ); - - Ok(event) - } - - pub fn to_succinct_avail_event(&self, id: &str) -> AvailResult { - let event = SuccinctAvailEvent::new( - id.to_string(), - self.to.clone(), - None, - self.amount.clone(), - self.fee.clone(), - self.message.clone(), - self.event_type.clone(), - self.state.clone(), - self.created, - self.executed_program_id.clone(), - self.executed_function_id.clone(), - ); - - Ok(event) - } - - pub fn decrypt_to_event(encrypted_transition: EncryptedData) -> AvailResult { - let v_key = VIEWSESSION.get_instance::()?; - - let db_id = match encrypted_transition.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - let encrypted_data = encrypted_transition.to_enrypted_struct::()?; - - let transition: TransactionPointer = encrypted_data.decrypt(v_key)?; - - transition.to_event(&db_id) - } - - pub fn decrypt_to_avail_event(encrypted_transaction: EncryptedData) -> AvailResult { - let v_key = VIEWSESSION.get_instance::()?; - - let db_id = match encrypted_transaction.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - let encrypted_data = encrypted_transaction.to_enrypted_struct::()?; - - let transaction: TransactionPointer = encrypted_data.decrypt(v_key)?; - - transaction.to_avail_event(&db_id) - } - - pub fn decrypt_to_succinct_avail_event( - encrypted_transaction: EncryptedData, - ) -> AvailResult { - let v_key = VIEWSESSION.get_instance::()?; - - let db_id = match encrypted_transaction.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - let encrypted_data = encrypted_transaction.to_enrypted_struct::()?; - - let transaction: TransactionPointer = encrypted_data.decrypt(v_key)?; - - transaction.to_succinct_avail_event(&db_id) - } -} - -/// A transition executed by the wallet owner in a transaction -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -pub struct ExecutedTransition { - program_id: String, - function_id: String, - transition_id: N::TransitionID, -} - -impl ExecutedTransition { - pub fn new(program_id: String, function_id: String, transition_id: N::TransitionID) -> Self { - Self { - program_id, - function_id, - transition_id, - } - } - - pub fn program_id(&self) -> String { - self.program_id.clone() - } - - pub fn function_id(&self) -> String { - self.function_id.clone() - } - - pub fn transition_id(&self) -> N::TransitionID { - self.transition_id.clone() - } - - pub fn to_event_transition( - &self, - view_key: ViewKey, - transaction: &transaction::Transaction, - ) -> AvailResult { - let transition = match transaction.find_transition(&self.transition_id) { - Some(transition) => transition, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Transition not found".to_string(), - "Transition not found".to_string(), - )) - } - }; - - let (inputs, outputs) = DecryptTransition::decrypt_inputs_outputs(view_key, transition)?; - - let event_transition = EventTransition::new( - self.transition_id.to_string(), - self.program_id(), - self.function_id(), - inputs, - outputs, - ); - - Ok(event_transition) - } -} - -#[derive(Debug, Clone)] -pub struct TransferResponse { - pub(crate) transaction_id: N::TransactionID, - pub(crate) block_height: u32, - pub(crate) spent_input_commitment: String, - pub(crate) spent_fee_commitment: String, - pub(crate) pending_tx_id: String, -} - -impl Display for TransferResponse { - fn fmt(&self, f: &mut Formatter<'_>) -> Res { - write!(f, "tx_id: {} \n block_height: {} \n spent_input_commitment: {} \n spent_fee_commitment: {}", self.transaction_id,self.block_height,self.spent_input_commitment,self.spent_fee_commitment) - } -} diff --git a/backend/src/models/pointers/transition.rs b/backend/src/models/pointers/transition.rs deleted file mode 100644 index 9c482570..00000000 --- a/backend/src/models/pointers/transition.rs +++ /dev/null @@ -1,357 +0,0 @@ -use avail_common::models::traits::encryptable::EncryptedStruct; -use chrono::{DateTime, Local}; -use serde::{Deserialize, Serialize}; -use snarkvm::prelude::{Address, Network}; -use uuid::Uuid; - -use crate::api::aleo_client::setup_client; -use crate::models::event::{ - AvailEvent, Event, EventTransition, Network as EventNetwork, SuccinctAvailEvent, Visibility, -}; -use crate::services::local_storage::{ - persistent_storage::{get_address, get_address_string, get_network}, - session::view::VIEWSESSION, -}; -use crate::services::record_handling::decrypt_transition::DecryptTransition; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::{ - encrypted_data::{ - EncryptedData, EncryptedDataRecord, EncryptedDataTypeCommon, EventStatus, - EventTypeCommon, TransactionState, - }, - traits::encryptable::Encryptable, - }, -}; - -// Pointer to a transition the wallet owner has received from or been a part of -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TransitionPointer { - pub id: N::TransitionID, - pub transaction_id: N::TransactionID, - pub program_id: String, - pub function_id: String, - pub timestamp: DateTime, - pub transition_type: TransitionType, - pub message: Option, - pub from: Option, - pub amount: Option, - pub block_height: u32, -} - -fn decrypt(encrypted_struct: EncryptedStruct) -> AvailResult> { - let view_key = VIEWSESSION.get_instance::()?; - let transition: TransitionPointer = encrypted_struct.decrypt(view_key)?; - - Ok(transition) -} - -impl TransitionPointer { - pub fn new( - id: N::TransitionID, - transaction_id: N::TransactionID, - program_id: String, - function_id: String, - timestamp: DateTime, - transition_type: TransitionType, - message: Option, - from: Option, - amount: Option, - block_height: u32, - ) -> Self { - Self { - id, - transaction_id, - program_id, - function_id, - timestamp, - transition_type, - message, - from, - amount, - block_height, - } - } - - pub fn to_encrypted_data(&self, encrypt_for: Address) -> AvailResult { - let encrypted_record_pointer = self.encrypt_for(encrypt_for)?; - - let network = get_network()?; - let id = Uuid::new_v4(); - let flavour = EncryptedDataTypeCommon::Transition; - let created_at = chrono::Utc::now(); - - let encrypted_data = EncryptedData::new( - Some(id), - encrypt_for.to_string(), - encrypted_record_pointer.cipher_text.to_string(), - encrypted_record_pointer.nonce.to_string(), - flavour, - None, - Some(self.program_id.clone()), - Some(self.function_id.clone()), - created_at, - None, - None, - network, - None, - None, - Some(self.transition_type.to_event_type()), - None, - None, - ); - - Ok(encrypted_data) - } - - pub fn to_encrypted_data_from_record( - encrypted_data_record: EncryptedDataRecord, - ) -> AvailResult { - let address = get_address::()?; - let encrypted_struct = encrypted_data_record.to_enrypted_struct::()?; - let record = decrypt::(encrypted_struct)?; - let encrypted_data = record.to_encrypted_data(address)?; - Ok(encrypted_data) - } - - pub fn to_event(&self, id: &str) -> AvailResult { - let address = get_address_string()?; - let network = get_network()?; - let event_network = match EventNetwork::from_str(&network) { - Some(network) => network, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Network not found".to_string(), - "Network not found".to_string(), - )) - } - }; - - let api_client = setup_client::()?; - let transaction = api_client.get_transaction(self.transaction_id)?; - - let transition = match transaction.find_transition(&self.id) { - Some(transition) => transition, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Transition not found".to_string(), - "Transition not found".to_string(), - )) - } - }; - - let view_key = VIEWSESSION.get_instance::()?; - - let (inputs, outputs) = DecryptTransition::decrypt_inputs_outputs(view_key, transition)?; - - let event_transition = EventTransition::new( - self.id.to_string(), - self.program_id.clone(), - self.function_id.clone(), - inputs.clone(), - outputs, - ); - - let event = Event::new( - id.to_string(), - self.transition_type.to_event_type(), - address, - EventStatus::Settled, - self.timestamp, - None, - None, - None, - event_network, - Some(self.transaction_id.to_string()), - Some(self.program_id.clone()), - Some(self.function_id.clone()), - inputs, - vec![event_transition], - None, - None, - None, - None, - Visibility::Private, - None, - ); - - Ok(event) - } - - pub fn to_avail_event(&self, id: &str) -> AvailResult { - let address = get_address_string()?; - let network = get_network()?; - let event_network = match EventNetwork::from_str(&network) { - Some(network) => network, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Network not found".to_string(), - "Network not found".to_string(), - )) - } - }; - - let api_client = setup_client::()?; - - let transaction = api_client.get_transaction(self.transaction_id)?; - - let transition = match transaction.find_transition(&self.id) { - Some(transition) => transition, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Transition not found".to_string(), - "Transition not found".to_string(), - )) - } - }; - - let view_key = VIEWSESSION.get_instance::()?; - - let (inputs, outputs) = DecryptTransition::decrypt_inputs_outputs(view_key, transition)?; - - let event_transition = EventTransition::new( - self.id.to_string(), - self.program_id.clone(), - self.function_id.clone(), - inputs.clone(), - outputs, - ); - - //TODO - Fix Visibility - let event = AvailEvent::new( - id.to_string(), - self.transition_type.to_event_type(), - address, - TransactionState::Confirmed, - self.timestamp, - None, - None, - None, - event_network, - Some(self.transaction_id.to_string()), - Some(self.program_id.clone()), - Some(self.function_id.clone()), - inputs, - vec![event_transition], - None, - None, - None, - None, - Visibility::Private, - None, - self.message.clone(), - None, - self.from.clone(), - self.amount.clone(), - ); - - Ok(event) - } - - pub fn to_succinct_avail_event(&self, id: &str) -> AvailResult { - let event = SuccinctAvailEvent::new( - id.to_string(), - None, - self.from.clone(), - self.amount.clone(), - None, - self.message.clone(), - self.transition_type.to_event_type(), - TransactionState::Confirmed, - self.timestamp, - Some(self.program_id.clone()), - Some(self.function_id.clone()), - ); - - Ok(event) - } - - pub fn decrypt_to_event(encrypted_transition: EncryptedData) -> AvailResult { - let v_key = VIEWSESSION.get_instance::()?; - - let db_id = match encrypted_transition.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - let encrypted_data = encrypted_transition.to_enrypted_struct::()?; - - let transition: TransitionPointer = encrypted_data.decrypt(v_key)?; - - transition.to_event(&db_id) - } - - pub fn decrypt_to_avail_event(encrypted_transition: EncryptedData) -> AvailResult { - let v_key = VIEWSESSION.get_instance::()?; - - let db_id = match encrypted_transition.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - let encrypted_data = encrypted_transition.to_enrypted_struct::()?; - - let transition: TransitionPointer = encrypted_data.decrypt(v_key)?; - - transition.to_avail_event(&db_id) - } - - pub fn decrypt_to_succinct_avail_event( - encrypted_transition: EncryptedData, - ) -> AvailResult { - let v_key = VIEWSESSION.get_instance::()?; - - let db_id = match encrypted_transition.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - let encrypted_data = encrypted_transition.to_enrypted_struct::()?; - - let transition: TransitionPointer = encrypted_data.decrypt(v_key)?; - - transition.to_succinct_avail_event(&db_id) - } - - pub fn is_fee(&self) -> bool { - match self.transition_type { - TransitionType::Fee => true, - _ => false, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum TransitionType { - Input, - Output, - Event, - Fee, -} - -impl TransitionType { - pub fn to_event_type(&self) -> EventTypeCommon { - match self { - TransitionType::Input => EventTypeCommon::Send, - TransitionType::Output => EventTypeCommon::Receive, - _ => EventTypeCommon::Execute, // fees - } - } -} diff --git a/backend/src/models/storage/encryption.rs b/backend/src/models/storage/encryption.rs deleted file mode 100644 index 82397fc6..00000000 --- a/backend/src/models/storage/encryption.rs +++ /dev/null @@ -1,48 +0,0 @@ -#![allow(dead_code)] - -use std::fmt::Display; - -use snarkvm::{console::prelude::*, prelude::*}; - -pub enum EncryptedData { - PrivateKey, - ViewKey, -} - -#[derive(PartialEq, Eq, Debug)] -pub enum Keys { - PrivateKey(PrivateKey), - ViewKey(ViewKey), -} - -impl Keys { - pub fn to_bytes_le(&self) -> Result, Error> { - match self { - Keys::PrivateKey(key) => key.to_bytes_le(), - Keys::ViewKey(key) => key.to_bytes_le(), - } - } - - pub fn is_private_key(&self) -> Option> { - match self { - Keys::PrivateKey(pk) => Some(*pk), - Keys::ViewKey(_) => None, - } - } - - pub fn is_view_key(&self) -> Option> { - match self { - Keys::PrivateKey(_) => None, - Keys::ViewKey(vk) => Some(*vk), - } - } -} - -impl Display for Keys { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Keys::PrivateKey(key) => write!(f, "{}", key), - Keys::ViewKey(key) => write!(f, "{}", key), - } - } -} diff --git a/backend/src/models/storage/languages.rs b/backend/src/models/storage/languages.rs deleted file mode 100644 index e6561d4b..00000000 --- a/backend/src/models/storage/languages.rs +++ /dev/null @@ -1,84 +0,0 @@ -use bip39::Language; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum Languages { - English, - ChineseSimplified, - ChineseTraditional, - Russian, - Spanish, - Italian, - Turkish, - Estonian, - Lithuanian, - Latvian, - Dutch, - Japanese, -} - -impl Languages { - pub fn to_string(&self) -> String { - match self { - Languages::English => "English".to_string(), - Languages::ChineseSimplified => "Chinese Simplified".to_string(), - Languages::ChineseTraditional => "Chinese Traditional".to_string(), - Languages::Russian => "Russian".to_string(), - Languages::Spanish => "Spanish".to_string(), - Languages::Italian => "Italian".to_string(), - Languages::Turkish => "Turkish".to_string(), - Languages::Estonian => "Estonian".to_string(), - Languages::Lithuanian => "Lithuanian".to_string(), - Languages::Latvian => "Latvian".to_string(), - Languages::Dutch => "Dutch".to_string(), - Languages::Japanese => "Japanese".to_string(), - } - } - - pub fn to_string_short(&self) -> String { - match self { - Languages::English => "en".to_string(), - Languages::ChineseSimplified => "zh-cn".to_string(), - Languages::ChineseTraditional => "zh-tw".to_string(), - Languages::Russian => "ru".to_string(), - Languages::Spanish => "es".to_string(), - Languages::Italian => "it".to_string(), - Languages::Turkish => "tr".to_string(), - Languages::Estonian => "et".to_string(), - Languages::Lithuanian => "lt".to_string(), - Languages::Latvian => "lv".to_string(), - Languages::Dutch => "nl".to_string(), - Languages::Japanese => "ja".to_string(), - } - } - - pub fn from_string_short(s: &str) -> Option { - match s { - "en" => Some(Languages::English), - "zh-cn" => Some(Languages::ChineseSimplified), - "zh-tw" => Some(Languages::ChineseTraditional), - "ru" => Some(Languages::Russian), - "es" => Some(Languages::Spanish), - "it" => Some(Languages::Italian), - "tr" => Some(Languages::Turkish), - "et" => Some(Languages::Estonian), - "lt" => Some(Languages::Lithuanian), - "lv" => Some(Languages::Latvian), - "nl" => Some(Languages::Dutch), - "ja" => Some(Languages::Japanese), - _ => None, - } - } - - pub fn to_bip39_language(&self) -> Language { - match self { - Languages::English => Language::English, - Languages::ChineseSimplified => Language::ChineseSimplified, - Languages::ChineseTraditional => Language::ChineseTraditional, - Languages::Spanish => Language::Spanish, - Languages::Italian => Language::Italian, - Languages::Japanese => Language::Japanese, - _ => Language::English, - } - } -} diff --git a/backend/src/models/storage/mod.rs b/backend/src/models/storage/mod.rs deleted file mode 100644 index 68d20e5e..00000000 --- a/backend/src/models/storage/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod encryption; -pub mod languages; -pub mod persistent; diff --git a/backend/src/models/storage/persistent.rs b/backend/src/models/storage/persistent.rs deleted file mode 100644 index 15ad0a26..00000000 --- a/backend/src/models/storage/persistent.rs +++ /dev/null @@ -1,132 +0,0 @@ -use app_dirs::*; -use rusqlite::{ - params_from_iter, - types::{FromSql, ToSql}, - Connection, -}; - -use avail_common::errors::AvailResult; - -pub struct PersistentStorage { - pub conn: Connection, - db_path: String, -} - -impl PersistentStorage { - ///Creates a new instance of PersistentStorage - pub fn new() -> AvailResult { - let path = app_root( - AppDataType::UserData, - &AppInfo { - name: "avail_wallet", - author: "Avail", - }, - )?; - - let db_path = path.into_os_string().into_string().unwrap(); - - let conn = Connection::open(format!("{}/persistent.db", db_path))?; - - Ok(PersistentStorage { conn, db_path }) - } - - /// Create a table within the database with an SQL query - pub fn execute_query(&self, query: &str) -> AvailResult<()> { - self.conn.execute(query, ())?; - - Ok(()) - } - - /// Save a vector of items of the same type to a table within the database with an SQL query - pub fn save(&self, data: Vec, query: String) -> AvailResult<()> { - let _insert = self.conn.execute( - &query, - //map data to params i.e data -> item1, item2 .. - params_from_iter(data.into_iter()), - )?; - - Ok(()) - } - - // Save a vector of items to a table within the database with an SQL query and allow for different types - pub fn save_mixed(&self, data: Vec<&dyn ToSql>, query: String) -> AvailResult<()> { - let _insert = self.conn.execute( - &query, - //map data to params i.e data -> item1, item2 .. - params_from_iter(data.into_iter()), - )?; - - Ok(()) - } - - /// Fetch a vector of items of the same type from a table within the database with an SQL query - pub fn get(&self, query: String, item_count: usize) -> AvailResult> { - let mut statement = self.conn.prepare(&query)?; - - let mut key_iter = statement.query_map([], |row| { - let data: Vec = (0..item_count).flat_map(|i| row.get(i)).collect(); - - Ok(data) - })?; - - let vec = key_iter.next().unwrap().unwrap(); - - Ok(vec) - } - - /// Fetch a vector of items of the same type from a table within the database with an SQL query - pub fn get_all(&self, query: &str, item_count: usize) -> AvailResult>> { - let mut statement = self.conn.prepare(query)?; - - let key_iter = statement.query_map([], |row| { - let data = (0..item_count).flat_map(|i| row.get(i)).collect(); - Ok(data) - })?; - - let key_vec = key_iter - .map(|key| match key { - Ok(key) => key, - Err(_) => Vec::new(), - }) - .collect::>>(); - - Ok(key_vec) - } -} -#[test] -fn test_save() { - let storage = PersistentStorage::new().unwrap(); - - //create table test - let query = "CREATE TABLE IF NOT EXISTS test (name TEXT, color TEXT)"; - - let _res = storage.execute_query(query).unwrap(); - - let query = "INSERT INTO test (name, color) VALUES (?, ?)".to_string(); - - let data = vec!["test".to_string(), "blue".to_string()]; - - let _res = storage.save(data, query).unwrap(); - - //then test getting data from the database - let query = "SELECT name, color FROM test".to_string(); - - let res = storage.get::(query, 2).unwrap(); - - assert_eq!(res[0], "test".to_string()); - assert_eq!(res[1], "blue".to_string()); -} - -#[test] -fn test_get() { - let storage = PersistentStorage::new().unwrap(); - //then test getting data from the database - let query = "SELECT name, color FROM test".to_string(); - - let res = storage.get::(query, 2).unwrap(); - - print!("{:?}", res); - - assert_eq!(res[0], "test".to_string()); - assert_eq!(res[1], "blue".to_string()); -} diff --git a/backend/src/models/transfer.rs b/backend/src/models/transfer.rs deleted file mode 100644 index 0b4e1ae4..00000000 --- a/backend/src/models/transfer.rs +++ /dev/null @@ -1,83 +0,0 @@ -use avail_common::aleo_tools::program_manager::TransferType; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct TransferRequest { - recipient: String, - amount: u64, - message: Option, - password: Option, - transfer_type: u8, - fee_private: bool, - fee: u64, - asset_id: String, -} - -impl TransferRequest { - pub fn new( - recipient: String, - amount: u64, - message: Option, - password: Option, - transfer_type: TransferType, - fee_private: bool, - fee: u64, - asset_id: String, - ) -> Self { - let transfer_type = match transfer_type { - TransferType::Public => 0, - TransferType::Private => 1, - TransferType::PublicToPrivate => 2, - TransferType::PrivateToPublic => 3, - }; - - Self { - recipient, - amount, - message, - password, - transfer_type, - fee_private, - fee, - asset_id, - } - } - - pub fn recipient(&self) -> &String { - &self.recipient - } - - pub fn amount(&self) -> &u64 { - &self.amount - } - - pub fn message(&self) -> &Option { - &self.message - } - - pub fn password(&self) -> &Option { - &self.password - } - - pub fn transfer_type(&self) -> &TransferType { - match &self.transfer_type { - 0 => &TransferType::Public, - 1 => &TransferType::Private, - 2 => &TransferType::PublicToPrivate, - 3 => &TransferType::PrivateToPublic, - _ => &TransferType::Private, - } - } - - pub fn fee_private(&self) -> &bool { - &self.fee_private - } - - pub fn fee(&self) -> &u64 { - &self.fee - } - - pub fn asset_id(&self) -> &String { - &self.asset_id - } -} diff --git a/backend/src/models/wallet.rs b/backend/src/models/wallet.rs deleted file mode 100644 index 79ce1f6e..00000000 --- a/backend/src/models/wallet.rs +++ /dev/null @@ -1,269 +0,0 @@ -use bip39::{Mnemonic, MnemonicType, Seed}; -use snarkvm::{ - console::prelude::*, - prelude::{Address, PrivateKey, ViewKey}, -}; - -use avail_common::errors::{AvailError, AvailResult}; -use zeroize::Zeroize; - -use crate::models::storage::languages::Languages; - -#[derive(Debug)] -pub struct BetterAvailWallet { - pub address: Address, - pub view_key: ViewKey, - pub private_key: PrivateKey, - pub mnemonic: Option, -} - -impl PartialEq for BetterAvailWallet { - fn eq(&self, other: &Self) -> bool { - self.private_key == other.private_key - && self.address == other.address - && self.view_key == other.view_key - } -} - -impl Eq for BetterAvailWallet {} - -impl BetterAvailWallet { - /// Generates a new [`BetterAvailWallet`], whilst throwing an error if the seed phrase length is not 12, 15, 18, 21, or 24. - /// - /// ``` - /// use availx_lib::models::wallet::BetterAvailWallet; - /// # use availx_lib::models::storage::languages::Languages; - /// # use snarkvm::prelude::Testnet3; - /// - /// let wallet = BetterAvailWallet::::new(24, &Languages::English); - /// - /// assert!(wallet.is_ok()); - /// ``` - pub fn new(seed_phrase_len: usize, seed_lang: &Languages) -> AvailResult { - let mnemonic = Mnemonic::new( - MnemonicType::for_word_count(seed_phrase_len)?, - Languages::to_bip39_language(seed_lang), - ); - - // NOTE: EMPTY BECAUSE WE ARE NOT USING PASSWORDS FOR SPs - let seed = Seed::new(&mnemonic, ""); - - Self::from_mnemonic_seed(seed, mnemonic) - } - - /// This method returns the bytes of the [`Field`] used to derive an Aleo [(docs)](https://developer.aleo.org/concepts/accounts#create-an-account) [`PrivateKey`]. - /// - /// Not to be confused with [`Seed`]. - pub fn get_seed_bytes(&self) -> AvailResult> { - let seed_bytes = self.private_key.to_bytes_le()?; - - Ok(seed_bytes) - } - - /// Generates an [`AvailWallet`] from an arbitrary seed phrase, using the specified [`Language`]. - pub fn from_seed_phrase(seed_phrase: &str, lang: bip39::Language) -> AvailResult { - let mnemonic = Mnemonic::from_phrase(seed_phrase, lang)?; - let seed = Seed::new(&mnemonic, ""); - - Self::from_mnemonic_seed(seed, mnemonic) - } - - /// Generates a [`BetterAvailWallet`] from the [`Seed`] of a [`Mnemonic`]. - pub fn from_mnemonic_seed(seed: Seed, mnemonic: Mnemonic) -> AvailResult { - let bytes = &mut seed.as_bytes()[0..=32].to_vec(); - - let field = ::Field::from_bytes_le_mod_order(bytes); - - let private_key = - PrivateKey::::try_from(FromBytes::read_le(&*field.to_bytes_le().unwrap()).unwrap())?; - - bytes.zeroize(); - - let view_key = ViewKey::::try_from(&private_key)?; - let address = Address::::try_from(&private_key)?; - - Ok(BetterAvailWallet:: { - address, - view_key, - private_key, - mnemonic: Some(mnemonic), - }) - } - - /// Gets the private key string of an avail wallet. - pub fn get_private_key(&self) -> String { - self.private_key.to_string() - } - - /// Gets the view key string of an avail wallet. - pub fn get_view_key(&self) -> String { - self.view_key.to_string() - } - - /// Gets the address string of an avail wallet. - pub fn get_address(&self) -> String { - self.address.to_string() - } - - pub fn get_network(&self) -> String { - N::NAME.to_string() - } -} - -/// Implementing the `Display` trait for the `BetterAvailWallet` struct. -impl Display for BetterAvailWallet { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.private_key) - } -} - -/// Implementing the `TryFrom` trait for the `BetterAvailWallet` struct. -impl TryFrom for BetterAvailWallet { - type Error = AvailError; - - fn try_from(value: String) -> AvailResult { - let private_key = PrivateKey::::from_str(&value)?; - let view_key = ViewKey::::try_from(&private_key)?; - let address = Address::::try_from(&private_key)?; - - Ok(BetterAvailWallet:: { - address, - view_key, - private_key, - mnemonic: None, - }) - } -} - -impl TryFrom<&str> for BetterAvailWallet { - type Error = AvailError; - - fn try_from(value: &str) -> AvailResult { - let private_key = PrivateKey::::from_str(value)?; - let view_key = ViewKey::::try_from(&private_key)?; - let address = Address::::try_from(&private_key)?; - - Ok(BetterAvailWallet:: { - address, - view_key, - private_key, - mnemonic: None, - }) - } -} - -impl TryFrom> for BetterAvailWallet { - type Error = AvailError; - - fn try_from(value: PrivateKey) -> AvailResult { - let view_key = ViewKey::::try_from(&value)?; - let address = Address::::try_from(&value)?; - - Ok(BetterAvailWallet:: { - address, - view_key, - private_key: value, - mnemonic: None, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use rstest::rstest; - use snarkvm::prelude::Testnet3; - - const PRIVATE_KEY: &str = "APrivateKey1zkpDqSfXcDcHdsvjkQhzF4NHTPPC63CBRHyaarTP3NAcHvg"; - const PHRASE: &str = "brave pass marine truly lecture fancy rail exotic destroy health always thunder wife decide situate index secret enter cruise prosper pudding about barely quit"; - - #[rstest] - fn test_create_random_avail_wallet(#[values(12, 15, 18, 21, 24)] seed_phrase_len: usize) { - let wallet = BetterAvailWallet::::new(seed_phrase_len, &Languages::English); - - assert!(wallet.is_ok()); - - let wallet = wallet.unwrap(); - println!("Wallet: {}", wallet.get_private_key()); - } - - #[rstest] - fn test_from_seed_bytes(#[values(12, 15, 18, 21, 24)] seed_phrase_len: usize) { - let mnemonic = Mnemonic::new( - MnemonicType::for_word_count(seed_phrase_len).unwrap(), - Languages::to_bip39_language(&Languages::English), - ); - - assert_eq!(mnemonic.phrase().split(" ").count(), seed_phrase_len); - - let seed = Seed::new(&mnemonic, ""); - let bytes = &mut seed.as_bytes()[0..32].to_vec(); - - assert_eq!(bytes.len(), 32); - - let wallet = BetterAvailWallet::::from_mnemonic_seed(seed, mnemonic); - - assert!(wallet.is_ok()); - } - - #[rstest] - /// Test that a wallet can be created from the seed phrase. - fn test_get_seed_bytes(#[values(12, 15, 18, 21, 24)] seed_phrase_len: usize) { - let wallet = - BetterAvailWallet::::new(seed_phrase_len, &Languages::English).unwrap(); - let seed_bytes = wallet.get_seed_bytes().unwrap(); - - assert_eq!(seed_bytes.len(), 32); - } - - #[rstest] - /// Test that an avail wallet can be created from the seed phrase. - fn test_from_seed_phrase() { - let mnemonic = Mnemonic::from_phrase(PHRASE, bip39::Language::English).unwrap(); - - let seed_phrase = mnemonic.phrase(); - - let wallet = BetterAvailWallet::::from_seed_phrase( - seed_phrase, - Languages::to_bip39_language(&Languages::English), - ); - - assert!(wallet.is_ok()); - - let wallet = wallet.unwrap(); - - assert_eq!(wallet.get_private_key(), PRIVATE_KEY) - } - - #[rstest] - /// Test that the private key string can be retrieved from the avail wallet. - fn test_get_private_key() { - let wallet = BetterAvailWallet::::try_from(PRIVATE_KEY).unwrap(); - let private_key = wallet.get_private_key(); - - assert_eq!(private_key, PRIVATE_KEY); - } - - #[rstest] - /// Test that the address string can be retrieved from the avail wallet. - fn test_get_view_key() { - let wallet = BetterAvailWallet::::try_from(PRIVATE_KEY).unwrap(); - let view_key = wallet.get_view_key(); - - assert_eq!( - view_key, - "AViewKey1icabKrKXiTjKnk1fd2p8NZ9etV8KZKNrejtiaHnav34N" - ); - } - - #[rstest] - fn test_get_address() { - let wallet = BetterAvailWallet::::try_from(PRIVATE_KEY).unwrap(); - let address = wallet.get_address(); - - assert_eq!( - address, - "aleo1lavuvpvklv3fdjwesr4pp5wekq2gjahu00krprnx8c2wc5xepuyqv64xk8" - ) - } -} diff --git a/backend/src/models/wallet_connect.rs b/backend/src/models/wallet_connect.rs deleted file mode 100644 index 679d27f9..00000000 --- a/backend/src/models/wallet_connect.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod balance; -pub mod create_event; -pub mod decrypt; -pub mod get_event; -pub mod records; -pub mod sign; diff --git a/backend/src/models/wallet_connect/balance.rs b/backend/src/models/wallet_connect/balance.rs deleted file mode 100644 index a244e4fe..00000000 --- a/backend/src/models/wallet_connect/balance.rs +++ /dev/null @@ -1,82 +0,0 @@ -use serde::{Deserialize, Serialize}; - -/* Balance Interfaces */ - -#[derive(Serialize, Deserialize, Debug)] -pub struct Balance { - public: f64, - private: f64, -} - -impl Balance { - pub fn public(&self) -> f64 { - self.public - } - - pub fn private(&self) -> f64 { - self.private - } - - pub fn total(&self) -> f64 { - self.public + self.private - } - - pub fn total_string(&self) -> String { - self.total().to_string() - } - - pub fn new(public: f64, private: f64) -> Self { - Self { public, private } - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct BalanceResponse { - balances: Vec, - error: Option, -} - -impl BalanceResponse { - pub fn new(balances: Vec, error: Option) -> Self { - Self { balances, error } - } - - pub fn balances(&self) -> &Vec { - &self.balances - } - - pub fn error(&self) -> Option<&String> { - self.error.as_ref() - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct BalanceRequest { - #[serde(rename = "assetId")] - asset_id: Option, - address: Option, -} - -impl BalanceRequest { - pub fn new(asset_id: Option<&str>, address: Option<&str>) -> Self { - let asset_id = match asset_id { - Some(asset_id) => Some(asset_id.to_string()), - None => None, - }; - - let address = match address { - Some(address) => Some(address.to_string()), - None => None, - }; - - Self { asset_id, address } - } - - pub fn asset_id(&self) -> Option { - self.asset_id.clone() - } - - pub fn address(&self) -> Option { - self.address.clone() - } -} diff --git a/backend/src/models/wallet_connect/create_event.rs b/backend/src/models/wallet_connect/create_event.rs deleted file mode 100644 index adab6bbb..00000000 --- a/backend/src/models/wallet_connect/create_event.rs +++ /dev/null @@ -1,80 +0,0 @@ -use avail_common::models::encrypted_data::EventTypeCommon; -use serde::{Deserialize, Serialize}; -/* Create Event Interfaces */ - -#[derive(Serialize, Deserialize, Debug)] -pub struct CreateEventRequest { - address: Option, - #[serde(rename = "type")] - event_type: EventTypeCommon, - #[serde(rename = "programId")] - program_id: String, - #[serde(rename = "functionId")] - function_id: String, - fee: f64, - inputs: Vec, -} - -impl CreateEventRequest { - pub fn new( - address: Option, - event_type: EventTypeCommon, - program_id: String, - function_id: String, - fee: f64, - inputs: Vec, - ) -> Self { - Self { - address, - event_type, - program_id, - function_id, - fee, - inputs, - } - } - - pub fn address(&self) -> Option<&String> { - self.address.as_ref() - } - - pub fn event_type(&self) -> &EventTypeCommon { - &self.event_type - } - - pub fn program_id(&self) -> &String { - &self.program_id - } - - pub fn function_id(&self) -> &String { - &self.function_id - } - - pub fn fee(&self) -> f64 { - self.fee - } - - pub fn inputs(&self) -> &Vec { - &self.inputs - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct CreateEventResponse { - event_id: Option, - error: Option, -} - -impl CreateEventResponse { - pub fn new(event_id: Option, error: Option) -> Self { - Self { event_id, error } - } - - pub fn event_id(&self) -> Option<&String> { - self.event_id.as_ref() - } - - pub fn error(&self) -> Option<&String> { - self.error.as_ref() - } -} diff --git a/backend/src/models/wallet_connect/decrypt.rs b/backend/src/models/wallet_connect/decrypt.rs deleted file mode 100644 index 11ba5ed8..00000000 --- a/backend/src/models/wallet_connect/decrypt.rs +++ /dev/null @@ -1,24 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct DecryptRequest { - pub ciphertexts: Vec, -} - -impl DecryptRequest { - pub fn new(ciphertexts: Vec) -> Self { - Self { ciphertexts } - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct DecryptResponse { - plaintexts: Vec, - error: Option, -} - -impl DecryptResponse { - pub fn new(plaintexts: Vec, error: Option) -> Self { - Self { plaintexts, error } - } -} diff --git a/backend/src/models/wallet_connect/deploy.rs b/backend/src/models/wallet_connect/deploy.rs deleted file mode 100644 index 8b137891..00000000 --- a/backend/src/models/wallet_connect/deploy.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/backend/src/models/wallet_connect/get_event.rs b/backend/src/models/wallet_connect/get_event.rs deleted file mode 100644 index 6d5810c5..00000000 --- a/backend/src/models/wallet_connect/get_event.rs +++ /dev/null @@ -1,123 +0,0 @@ -use crate::models::event::{AvailEvent, Event}; -use avail_common::models::encrypted_data::EventTypeCommon; -use serde::{Deserialize, Serialize}; - -/* Get Event Interfaces */ -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct GetEventRequest { - pub id: String, - pub address: Option, -} - -impl GetEventRequest { - pub fn new(id: String, address: Option) -> Self { - Self { id, address } - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct GetEventResponse { - pub event: Option, - pub error: Option, -} - -impl GetEventResponse { - pub fn new(event: Option, error: Option) -> Self { - Self { event, error } - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct GetAvailEventResponse { - pub event: Option, - pub error: Option, -} - -impl GetAvailEventResponse { - pub fn new(event: Option, error: Option) -> Self { - Self { event, error } - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct GetEventsRequest { - pub filter: Option, - pub page: Option, -} - -impl GetEventsRequest { - pub fn default() -> Self { - Self { - filter: Some(EventsFilter::default()), - page: Some(0), - } - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct EventsFilter { - #[serde(rename = "type")] - pub event_type: Option, - #[serde(rename = "programId")] - pub program_id: Option, - #[serde(rename = "functionId")] - pub function_id: Option, -} - -impl EventsFilter { - pub fn new( - event_type: Option, - program_id: Option, - function_id: Option, - ) -> Self { - Self { - event_type, - program_id, - function_id, - } - } - - pub fn default() -> Self { - Self { - event_type: None, - program_id: None, - function_id: None, - } - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct GetEventsResponse { - pub events: Vec, - #[serde(rename = "pageCount")] - pub page_count: Option, - pub error: Option, -} - -impl GetEventsResponse { - pub fn new(events: Vec, page_count: Option, error: Option) -> Self { - Self { - events, - page_count, - error, - } - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct GetAvailEventsResponse { - pub events: Vec, - #[serde(rename = "pageCount")] - pub page_count: Option, - pub error: Option, -} - -impl GetAvailEventsResponse { - pub fn new(events: Vec, page_count: Option, error: Option) -> Self { - Self { - events, - page_count, - error, - } - } -} diff --git a/backend/src/models/wallet_connect/records.rs b/backend/src/models/wallet_connect/records.rs deleted file mode 100644 index e9286172..00000000 --- a/backend/src/models/wallet_connect/records.rs +++ /dev/null @@ -1,203 +0,0 @@ -use crate::models::pointers::record::AvailRecord; -use avail_common::errors::AvailResult; -use serde::{Deserialize, Serialize}; -use snarkvm::console::program::Network; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct GetRecordsRequest { - address: Option, - filter: Option, - page: Option, -} - -impl GetRecordsRequest { - pub fn new(address: Option, filter: Option, page: Option) -> Self { - Self { - address, - filter, - page, - } - } - pub fn address(&self) -> &Option { - &self.address - } - - pub fn filter(&self) -> &Option { - &self.filter - } - - pub fn page(&self) -> &Option { - &self.page - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct RecordsFilter { - #[serde(rename = "programIds")] - program_ids: Vec, - #[serde(rename = "functionId")] - function_id: Option, - #[serde(rename = "type")] - record_type: String, - record_name: Option, -} - -impl RecordsFilter { - pub fn new( - program_ids: Vec, - function_id: Option, - record_type: RecordFilterType, - record_name: Option, - ) -> Self { - Self { - program_ids, - function_id, - record_type: record_type.to_string(), - record_name, - } - } - - pub fn program_ids(&self) -> &Vec { - &self.program_ids - } - - pub fn function_id(&self) -> &Option { - &self.function_id - } - - pub fn record_type(&self) -> &String { - &self.record_type - } - - pub fn record_name(&self) -> &Option { - &self.record_name - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum RecordFilterType { - All, - Spent, - Unspent, -} - -impl RecordFilterType { - pub fn from_str(filter: &str) -> Self { - match filter { - "all" => RecordFilterType::All, - "spent" => RecordFilterType::Spent, - "unspent" => RecordFilterType::Unspent, - _ => RecordFilterType::All, - } - } - - pub fn to_string(&self) -> String { - match self { - RecordFilterType::All => "all".to_string(), - RecordFilterType::Spent => "spent".to_string(), - RecordFilterType::Unspent => "unspent".to_string(), - } - } - - pub fn from_string(filter: &String) -> &Self { - match filter.as_str() { - "all" => &RecordFilterType::All, - "spent" => &RecordFilterType::Spent, - "unspent" => &RecordFilterType::Unspent, - _ => &RecordFilterType::All, - } - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct GetRecordsResponse { - records: Vec, - #[serde(rename = "pageCount")] - page_count: Option, - error: Option, -} - -impl GetRecordsResponse { - pub fn new( - records: Vec, - page_count: Option, - error: Option, - ) -> Self { - Self { - records, - page_count, - error, - } - } - - pub fn records(&self) -> &Vec { - &self.records - } - - pub fn page_count(&self) -> &Option { - &self.page_count - } - - pub fn error(&self) -> &Option { - &self.error - } -} - -// A new struct for RecordWithPlaintext -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct RecordWithPlaintext { - pub record: wc_Record, - pub plaintext: String, - pub data: std::collections::HashMap, -} - -impl RecordWithPlaintext { - pub fn from_record_pointer( - record_pointer: AvailRecord, - id: String, - ) -> AvailResult { - let (plaintext, ciphertext, data) = record_pointer.to_record_texts_and_data()?; - - let record = wc_Record { - _id: id, - event_id: record_pointer.pointer.transaction_id.to_string(), - height: record_pointer.pointer.block_height, - ciphertext, - program_id: record_pointer.metadata.program_id, - function_id: record_pointer.metadata.function_id, - transition_id: record_pointer.pointer.transition_id.to_string(), - transaction_id: record_pointer.pointer.transaction_id.to_string(), - owner: record_pointer.pointer.owner, - spent: record_pointer.metadata.spent, - serial_number: None, - name: record_pointer.metadata.name, - }; - Ok(Self { - record, - plaintext, - data, - }) - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct wc_Record { - pub _id: String, // transaction id or commitment - #[serde(rename = "eventId")] - pub event_id: String, // transaction id - pub height: u32, - pub ciphertext: String, - #[serde(rename = "programId")] - pub program_id: String, - #[serde(rename = "functionId")] - pub function_id: String, - #[serde(rename = "transitionId")] - pub transition_id: String, - #[serde(rename = "transactionId")] - pub transaction_id: String, - pub owner: String, - pub spent: bool, - #[serde(rename = "serialNumber")] - pub serial_number: Option, // Fetch in .to_record() - pub name: String, -} diff --git a/backend/src/models/wallet_connect/sign.rs b/backend/src/models/wallet_connect/sign.rs deleted file mode 100644 index 7dbce9fd..00000000 --- a/backend/src/models/wallet_connect/sign.rs +++ /dev/null @@ -1,55 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct SignatureRequest { - message: String, - address: Option, -} - -impl SignatureRequest { - pub fn new(message: String, address: Option) -> Self { - Self { message, address } - } - - pub fn get_message(&self) -> String { - self.message.clone() - } - - pub fn get_address(&self) -> Option { - self.address.clone() - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct SignatureResponse { - signature: Option, - #[serde(rename = "messageFields")] - message_fields: Option, - error: Option, -} - -impl SignatureResponse { - pub fn new( - signature: Option, - message_fields: Option, - error: Option, - ) -> Self { - Self { - signature, - message_fields, - error, - } - } - - pub fn get_signature(&self) -> Option { - self.signature.clone() - } - - pub fn get_message_fields(&self) -> Option { - self.message_fields.clone() - } - - pub fn get_error(&self) -> Option { - self.error.clone() - } -} diff --git a/backend/src/services.rs b/backend/src/services.rs deleted file mode 100644 index 05b0ad84..00000000 --- a/backend/src/services.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod account; -pub mod authentication; -pub mod local_storage; -pub mod record_handling; -pub mod records; -pub mod wallet_connect_api; diff --git a/backend/src/services/README.md b/backend/src/services/README.md deleted file mode 100644 index 06762268..00000000 --- a/backend/src/services/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# Services Documentation - -## Overview - -This is the logic behind Avail wallet, this encapsulates account creation, handling of transactions and records, wallet recovery using shamir's secret sharing scheme and storing on the android/ios secure enclaves. - -## Services - -### generation.rs - -This is the initial generation of a wallet for a user. The wallet can either be without a seed phrase or with a seed phrase, if they have a seed phrase then they dont't make use of our recovery system. - -The user inputs a username and passoword and chooses if they would like to authenticate using biometrics. Once inputted an aleo keypair is generated and the local storage process starts, along with the sharding as preperation in case of recovery. The user can also choose to allow others to reference them by their username and in that case we store the username and address in Avail's database. - -### local_storage - -#### iOS - - For iOS we use the iOS keychain, a secure data storage system made by apple, to store the private key and this is protected either by the application password or biometrics. The private key is encrypted by an aes-key generated and stored in the keychain's secure enclave and this is non extractable. - - We use apple's `security-framework` and `local-authentication-framework` to access the keychain and authnetication functionalities. - -#### Android - -For android we use the android keystore, a secure data storage system made by google. This generates and stores a cryptographic key AES | RSA in a TEE (Trusted Execution Environment) or secure enclave to protect it from extraction. The key is protected by biometrics. Then we encrypt the private key and viewing key using the key in the keystore and store it in the android shared preferences. - -In the case of authenticating the user with application password, we hash the password using argon2, generate an aes key from the derived password hash and use that to encrypt a randomly generated aes-key. With the randomly generated aes-key we encrypt the private key and viewing key and store it an sqlite database embeded in the user's application data. The password hash is not stored locally and must be inputted by the user to authenticate and use the keys. - -### recovery.rs - -This process is only available to those who opt in and do kyc verification so we can prove their identity when they want to recover their wallet. - -Using Shamir's secret sharing scheme we split the private key into 3 encrypted shards and these are sent to three entities. These entities are the user's cloud, either iCloud keychain or Gdrive, Avail's secure data storage and our partner's secure data storage. Shamir is set in a way that 2 of the 3 shards is sufficient to reconstruct the original private key. - -By default the user's cloud and Avail's secure data storage is used for recovery. When a user wants to recover they do kyc verification and if verified the shard is sent from Avail to the user. Then the shards are reconstructed and the private key is stored locally on the user's device as explained in the local_storage section. - -If the shard is not present in the user's specified cloud then we must make use of the partner's secure data storage. Again in this case the user must do kyc verification and input their email address and if verified then recovery will start. We make it clear that in our system only one encrypted shard is ever being transferred using https. Therefore the user will receive two random emails along the following hours and each email will take them to the Avail app and initiate the recovery of a shard in that instance. This is done for security purposes, once both shards are recovered the private key is reconstructed and stored locally on the user's device as explained in the local_storage section. - -We will move research and develop a solution that stills verify the user without kyc as we move forward and innovate in the future. - -### records.rs - -This is the logic behind handling the records of the user locally i.e getting the user's balance and past transaction and filtering the transactions. Also this includes the transfer function allowing to send tokens to someone else on the aleo network.This is done using the aleo rust sdk. diff --git a/backend/src/services/account.rs b/backend/src/services/account.rs deleted file mode 100644 index 40910d35..00000000 --- a/backend/src/services/account.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod generation; -pub mod key_management; -pub mod phrase_recovery; -pub mod utils; diff --git a/backend/src/services/account/generation.rs b/backend/src/services/account/generation.rs deleted file mode 100644 index ed77904d..00000000 --- a/backend/src/services/account/generation.rs +++ /dev/null @@ -1,159 +0,0 @@ -use snarkvm::{console::prelude::*, prelude::Testnet3}; - -use crate::models::storage::languages::Languages; -use crate::services::account::{ - key_management::key_controller::KeyController, utils::generate_discriminant, -}; -use crate::services::authentication::session::get_session_after_creation; -use crate::services::local_storage::persistent_storage::get_language; -use crate::services::local_storage::{ - encrypted_data::{get_and_store_all_data, initialize_encrypted_data_table}, - persistent_storage::initial_user_preferences, - session::{password::PASS, view::VIEWSESSION}, - tokens::init_tokens_table, -}; -use crate::{api::user::create_user, models::wallet::BetterAvailWallet}; - -#[cfg(target_os = "linux")] -use crate::services::account::key_management::key_controller::linuxKeyController; - -#[cfg(target_os = "windows")] -use crate::services::account::key_management::key_controller::windowsKeyController; - -#[cfg(target_os = "macos")] -use crate::services::account::key_management::key_controller::macKeyController; - -use avail_common::{errors::AvailResult, models::user::User}; - -#[tauri::command(rename_all = "snake_case")] -pub async fn create_seed_phrase_wallet( - username: Option, - password: String, - access_type: bool, - backup: bool, - language: Languages, - length: usize, -) -> AvailResult { - let avail_wallet = BetterAvailWallet::::new(length, &language)?; - - let tag = username.clone().map(|_| generate_discriminant()); - - let user_request = User { - username: username.clone(), - address: avail_wallet.address.to_string(), - tag, - backup: false, - }; - - create_user(user_request).await?; - - //TODO: Change to mainnet on launch - initial_user_preferences( - access_type, - username, - tag, - false, - backup, - avail_wallet.address.to_string(), - language.clone(), - )?; - - init_tokens_table()?; - - initialize_encrypted_data_table()?; - - let key_manager = { - #[cfg(target_os = "windows")] - { - windowsKeyController {} - } - #[cfg(target_os = "linux")] - { - linuxKeyController {} - } - #[cfg(target_os = "macos")] - { - macKeyController {} - } - }; - - key_manager.store_key(&password, &avail_wallet)?; - - VIEWSESSION.set_view_session(&avail_wallet.get_view_key())?; - - PASS.set_pass_session(&password)?; - - get_session_after_creation(&avail_wallet.private_key).await?; - - // NOTE: We can safely unwrap here because we created - // the wallet using the [`BetterAvailWallet::new`] method - let seed_phrase = avail_wallet.mnemonic.unwrap().phrase().to_string(); - - Ok(seed_phrase) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn import_wallet( - username: Option, - password: String, - access_type: bool, - private_key: &str, - backup: bool, - language: Languages, -) -> AvailResult { - let avail_wallet = BetterAvailWallet::::try_from(private_key.to_string())?; - - let tag = username.clone().map(|_| generate_discriminant()); - - let user_request = User { - username: username.clone(), - address: avail_wallet.address.to_string(), - tag, - backup: false, - }; - - create_user(user_request).await?; - - initial_user_preferences( - access_type, - username, - tag, - false, - backup, - avail_wallet.address.to_string(), - language, - )?; - - init_tokens_table()?; - - initialize_encrypted_data_table()?; - - let key_manager = { - #[cfg(target_os = "windows")] - { - windowsKeyController {} - } - - #[cfg(target_os = "linux")] - { - linuxKeyController {} - } - - #[cfg(target_os = "macos")] - { - macKeyController {} - } - }; - - let storage = key_manager.store_key(&password, &avail_wallet)?; - - VIEWSESSION.set_view_session(&avail_wallet.view_key.to_string())?; - - PASS.set_pass_session(&password)?; - - get_session_after_creation(&avail_wallet.private_key).await?; - - get_and_store_all_data().await?; - - Ok(storage) -} diff --git a/backend/src/services/account/key_management.rs b/backend/src/services/account/key_management.rs deleted file mode 100644 index 866508bc..00000000 --- a/backend/src/services/account/key_management.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod desktop; -pub mod key_controller; diff --git a/backend/src/services/account/key_management/android.rs b/backend/src/services/account/key_management/android.rs deleted file mode 100644 index 899609b6..00000000 --- a/backend/src/services/account/key_management/android.rs +++ /dev/null @@ -1,719 +0,0 @@ -use avail_common::models::network::SupportedNetworks; -use jni::objects::{JByteArray, JClass, JMap, JObject, JString, JValue}; - -use jni::{JNIEnv, JavaVM}; -use ndk_context; -use snarkvm::prelude::*; -use std::ffi::c_void; - -use crate::api::{encrypted_data::delete_all_server_storage, user::delete_user}; - -use crate::models::{ - auth::Options, - storage::encryption::{EncryptedData, Keys, Keys::PrivateKey as PKey, Keys::ViewKey as VKey}, - wallet::AvailWallet, -}; - -use crate::services::local_storage::{ - persistent_storage::{ - delete_user_preferences, get_auth_type, get_network, remove_view_session, - }, - records_storage::delete_user_encrypted_data, - utils::encrypt_with_password, -}; - -use avail_common::{ - aleo_tools::encryptor::Encryptor, - errors::{AvailError, AvailErrorType, AvailResult}, -}; - -#[no_mangle] -#[allow(non_snake_case)] -pub extern "system" fn Java_com_example_keystore_KeyStoreModule_create( - mut env: JNIEnv, - class: JClass, - alias: JString, - p_key: JByteArray, - v_key: JByteArray, - options: JObject, - context: JObject, -) -> AvailResult<()> { - let j_context = JValue::Object(&context); - print!("Error cause of params?"); - let keystore_module = env.new_object(class, "(Landroid/content/Context;)V", &[j_context])?; - - let keystore_module_ref = env.new_global_ref(keystore_module)?; - - let j_alias = JValue::Object(&alias); - let j_pkey = JValue::Object(&p_key); - let j_vkey = JValue::Object(&v_key); - let j_options = JValue::Object(&options); - - let result = env.call_method( - keystore_module_ref, - "setGenericPassword", - "(Ljava/lang/String;[B[BLjava/util/Map;Landroid/content/Context;)Ljava/util/Map;", - &[j_alias, j_pkey, j_vkey, j_options, j_context], - )?; - - let exceptions = env.exception_occurred()?; - - if exceptions.is_null() { - println!("No exception occurred"); - } else { - println!("Exception occurred"); - env.exception_describe()?; - env.exception_clear()?; - } - - let result = result.l()?; - - println!("{:#?}", result); - Ok(()) -} - -#[allow(non_snake_case)] -pub extern "system" fn Java_com_example_keystore_KeyStoreModule_get( - mut env: JNIEnv, - class: JClass, - alias: JString, - options: JObject, - context: JObject, - key_type: JString, -) -> AvailResult> { - let j_context = JValue::Object(&context); - - let keystore_module = env.new_object(class, "(Landroid/content/Context;)V", &[j_context])?; - - let keystore_module_ref = env.new_global_ref(keystore_module)?; - - let j_alias = JValue::Object(&alias); - let j_options = JValue::Object(&options); - let j_key_type = JValue::Object(&key_type); - - let result = env.call_method( - keystore_module_ref, - "getGenericPassword", - "(Ljava/lang/String;Ljava/util/Map;Landroid/content/Context;Ljava/lang/String;)Ljava/util/Map;", - &[j_alias, j_options, j_context, j_key_type], - )?; - - let exceptions = env.exception_occurred()?; - if exceptions.is_null() { - println!("No exception occurred"); - } else { - println!("Exception occurred"); - env.exception_describe()?; - env.exception_clear()?; - } - - let result = result.l()?; - - //turn result to map then iterate through map to get values which are bytes - - let JMap = JMap::from_env(&mut env, &result)?; - - let mut iter = JMap.iter(&mut env)?; - - // there will be two key value pairs in the map, one for username and one for password - - let p_key_value = iter.next(&mut env)?; - - let p_key_value = match p_key_value { - Some(p) => p, - None => { - return Err(AvailError::new( - AvailErrorType::LocalStorage, - "No key value pair found".to_string(), - "No key value pair found".to_string(), - )) - } - }; - - let v_key_value = iter.next(&mut env)?; - - let v_key_value = match v_key_value { - Some(v) => v, - None => { - return Err(AvailError::new( - AvailErrorType::LocalStorage, - "No key value pair found".to_string(), - "No key value pair found".to_string(), - )) - } - }; - - let key_raw = p_key_value.1.as_raw(); - let key = unsafe { JByteArray::from_raw(key_raw) }; - let p_key = env.convert_byte_array(key)?; - - let key_raw = v_key_value.1.as_raw(); - let key = unsafe { JByteArray::from_raw(key_raw) }; - let v_key = env.convert_byte_array(key)?; - - // println!("PKbytes {:?}", p_key); - // print!("VKbytes {:?}", v_key); - - let key_type = env.get_string(&key_type)?; - let key_type = key_type.to_str(); - - let key_type = match key_type { - Ok(k) => k, - Err(_e) => { - return Err(AvailError::new( - AvailErrorType::LocalStorage, - "Error converting key type".to_string(), - "Error converting key type".to_string(), - )) - } - }; - match key_type { - "avl-p" => Ok(p_key), - "avl-v" => Ok(v_key), - _ => Err(AvailError::new( - AvailErrorType::InvalidData, - "Invalid key type".to_string(), - "Invalid key type".to_string(), - )), - } -} - -#[no_mangle] -#[allow(non_snake_case)] -pub extern "system" fn Java_com_example_keystore_KeyStoreModule_delete( - mut env: JNIEnv, - class: JClass, - alias: JString, - context: JObject, -) -> AvailResult<()> { - let j_context = JValue::Object(&context); - - let keystore_module = env.new_object(class, "(Landroid/content/Context;)V", &[j_context])?; - - let keystore_module_ref = env.new_global_ref(keystore_module)?; - - let j_alias = JValue::Object(&alias); - - let _result = env.call_method( - keystore_module_ref, - "resetGenericPassword", - "(Ljava/lang/String;)Z", - &[j_alias], - )?; - - let exceptions = env.exception_occurred()?; - - if exceptions.is_null() { - println!("No exception occurred"); - } else { - println!("Exception occurred"); - env.exception_describe()?; - env.exception_clear()?; - }; - - Ok(()) -} - -/// Checks if the device supports biometric authentication using jni -#[no_mangle] -#[allow(non_snake_case)] -pub extern "system" fn Java_com_example_keystore_KeyStoreModule_check( - mut env: JNIEnv, - class: JClass, - context: JObject, -) -> AvailResult { - let j_context = JValue::Object(&context); - - let keystore_module = env.new_object(class, "(Landroid/content/Context;)V", &[j_context])?; - - let keystore_module_ref = env.new_global_ref(keystore_module)?; - - let result = env.call_method( - keystore_module_ref, - "checkBio", - "(Landroid/content/Context;)Z", - &[j_context], - )?; - - let exceptions = env.exception_occurred()?; - - if exceptions.is_null() { - println!("No exception occurred"); - } else { - println!("Exception occurred"); - env.exception_describe()?; - env.exception_clear()?; - } - - Ok(result.z()?) -} - -/// Checks if the app has permission to use biometric authentication -#[no_mangle] -#[allow(non_snake_case)] -pub extern "system" fn Java_com_example_keystore_KeyStoreModule_permission( - mut env: JNIEnv, - class: JClass, - context: JObject, -) -> AvailResult { - let j_context = JValue::Object(&context); - - let keystore_module = env.new_object(class, "(Landroid/content/Context;)V", &[j_context])?; - - let keystore_module_ref = env.new_global_ref(keystore_module)?; - - let result = env.call_method( - keystore_module_ref, - "checkBiometryPermission", - "(Landroid/content/Context;)Z", - &[j_context], - )?; - - let exceptions = env.exception_occurred()?; - - if exceptions.is_null() { - println!("No exception occurred"); - } else { - println!("Exception occurred"); - env.exception_describe()?; - env.exception_clear()?; - } - - Ok(result.z()?) -} - -/// Creates a JVM instance and returns a tuple of the JVM and the activity context -fn prepare_jvm() -> AvailResult<(JavaVM, *mut c_void)> { - let ctx = ndk_context::android_context(); - let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }?; - - let activity = ctx.context(); - - Ok((vm, activity)) -} - -// TODO: Collect common code -> Having problems with lifetimes and borrowing - -///Creates or loads an instance of keystore, generating a protected RSA Key and stores -///encrypted username, encrypted password and salt in SharedPreferences. -#[tauri::command(rename_all = "snake_case")] -pub fn keystore_init( - password: &str, - access_type: bool, - p_key: &PrivateKey, - v_key: &ViewKey, -) -> AvailResult { - let mut auth_options = Options::default(); - - if access_type { - println!("Biometric access enabled"); - auth_options.accessControl = Some("BiometryCurrentSet".to_string()); - }; - - let (jvm, activity) = prepare_jvm()?; - - let _env = jvm.attach_current_thread()?; - - let mut env = jvm.get_env()?; - - let class = env.find_class("com/example/keystore/KeyStoreModule")?; - - let class2 = **class; - let class2 = unsafe { JClass::from_raw(class2) }; - - let service = env.new_string(auth_options.service)?; - let title = env.new_string(auth_options.title)?; - let subtitle = env.new_string(auth_options.subtitle)?; - let description = env.new_string(auth_options.description)?; - let cancel = env.new_string(auth_options.cancel)?; - let accessible = env.new_string(auth_options.accessible)?; - let security_level = env.new_string(auth_options.securityLevel)?; - - let mut access_control = JObject::from(env.new_string("None")?); - let acc = auth_options.accessControl; - - if let Some(a) = acc { - access_control = JObject::from(env.new_string(a)?); - } - - let mut storage = JObject::from(env.new_string("Best")?); - let sto = auth_options.storage; - - if let Some(s) = sto { - storage = JObject::from(env.new_string(s)?); - } - - let mut authentication_type = JObject::null(); - let aut = auth_options.authenticationType; - - if let Some(a) = aut { - authentication_type = JObject::from(env.new_string(a)?); - } - - let jservice = JValue::Object(&service); - let jtitle = JValue::Object(&title); - let jsubtitle = JValue::Object(&subtitle); - let jdescription = JValue::Object(&description); - let jcancel = JValue::Object(&cancel); - let jaccessible = JValue::Object(&accessible); - let jaccess_control = JValue::Object(&access_control); - let jstorage = JValue::Object(&storage); - let jsecurity_level = JValue::Object(&security_level); - let jauthentication_type = JValue::Object(&authentication_type); - - let result = env.call_static_method(class, "constructOptions", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/util/Map;", - &[jservice, jtitle, jsubtitle, jdescription, jcancel, jaccessible, jaccess_control, jstorage, jsecurity_level, jauthentication_type])?; - - let exceptions = env.exception_occurred()?; - - if exceptions.is_null() { - println!("No exception occurred"); - } else { - println!("Exception occurred"); - env.exception_describe()?; - env.exception_clear()?; - } - - let options = result.l()?; - - let alias = env.new_string("AV_KEYSTORE")?; - - let context = unsafe { JObject::from_raw(activity as jni::sys::jobject) }; - - match access_type { - true => { - let p_key = env.byte_array_from_slice(&p_key.to_bytes_le()?)?; - let v_key = env.byte_array_from_slice(&v_key.to_bytes_le()?)?; - Java_com_example_keystore_KeyStoreModule_create( - env, class2, alias, p_key, v_key, options, context, - )?; - } - false => { - let network = get_network()?; - print!("Got here son"); - let ciphertext_p = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - match encrypt_with_password::(password, PKey(*p_key)) { - Ok(c) => c, - Err(e) => { - println!("Error encrypting view key: {}", e); - return Err(AvailError::new( - AvailErrorType::Internal, - "Error encrypting private key".to_string(), - "Error encrypting private key".to_string(), - )); - } - } - } - }; - - let ciphertext_v = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - match encrypt_with_password::(password, VKey(*v_key)) { - Ok(c) => c, - Err(e) => { - println!("Error encrypting view key: {}", e); - return Err(AvailError::new( - AvailErrorType::Internal, - "Error encrypting view key".to_string(), - "Error encrypting view key".to_string(), - )); - } - } - } - }; - - let p_key = env.byte_array_from_slice(&ciphertext_p.to_bytes_le()?)?; - let v_key = env.byte_array_from_slice(&ciphertext_v.to_bytes_le()?)?; - - Java_com_example_keystore_KeyStoreModule_create( - env, class2, alias, p_key, v_key, options, context, - )?; - } - } - - Ok("Key stored".to_string()) -} - -///Uses the key in keystore to decrypt the hash stored in SharedPreferences. -#[tauri::command(rename_all = "snake_case")] -pub fn keystore_load(password: Option<&str>, key_type: &str) -> AvailResult> { - let auth_options = Options::default(); - let auth_type = get_auth_type()?; - - if !auth_type { - let _pass = password.ok_or(AvailError::new( - AvailErrorType::Internal, - "Login".to_string(), - "Login".to_string(), - ))?; - }; - - let (jvm, activity) = prepare_jvm()?; - - jvm.attach_current_thread()?; - - let mut env = jvm.get_env()?; - - let class = env.find_class("com/example/keystore/KeyStoreModule")?; - - let class2 = **class; - let class2 = unsafe { JClass::from_raw(class2) }; - - let service = env.new_string(auth_options.service)?; - let title = env.new_string(auth_options.title)?; - let subtitle = env.new_string(auth_options.subtitle)?; - let description = env.new_string(auth_options.description)?; - let cancel = env.new_string(auth_options.cancel)?; - let accessible = env.new_string(auth_options.accessible)?; - //let storage = env.new_string(auth_options.storage?)?; - let security_level = env.new_string(auth_options.securityLevel)?; - // let authentication_type = env.new_string(auth_options.authenticationType?)?; - - let mut access_control = JObject::from(env.new_string("None")?); - - if auth_type.as_str() == "true" { - access_control = JObject::from(env.new_string("BiometryCurrentSet")?); - } - - let mut storage = JObject::from(env.new_string("KeystoreRSAECB")?); - let sto = auth_options.storage; - - if let Some(s) = sto { - storage = JObject::from(env.new_string(s)?); - } - - let mut authentication_type = JObject::null(); - let aut = auth_options.authenticationType; - - if let Some(a) = aut { - authentication_type = JObject::from(env.new_string(a)?); - } - - let jservice = JValue::Object(&service); - let jtitle = JValue::Object(&title); - let jsubtitle = JValue::Object(&subtitle); - let jdescription = JValue::Object(&description); - let jcancel = JValue::Object(&cancel); - let jaccessible = JValue::Object(&accessible); - let jaccess_control = JValue::Object(&access_control); - let jstorage = JValue::Object(&storage); - let jsecurity_level = JValue::Object(&security_level); - let jauthentication_type = JValue::Object(&authentication_type); - - let result = env.call_static_method(class, "constructOptions", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/util/Map;", - &[jservice, jtitle, jsubtitle, jdescription, jcancel, jaccessible, jaccess_control, jstorage, jsecurity_level, jauthentication_type])?; - - let exceptions = env.exception_occurred()?; - - if exceptions.is_null() { - println!("No exception occurred for options"); - } else { - println!("Exception occurred for options"); - env.exception_describe()?; - env.exception_clear()?; - } - - let options = result.l()?; - let jkey_type = env.new_string(key_type.to_string())?; - let alias = env.new_string("AV_KEYSTORE")?; - let context = unsafe { JObject::from_raw(activity as jni::sys::jobject) }; - - let auth = match auth_type.as_str() { - "true" => true, - "false" => false, - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error getting auth type".to_string(), - "Error getting auth type".to_string(), - )) - } - }; - - print!("Before failure"); - let key = Java_com_example_keystore_KeyStoreModule_get( - env, class2, alias, options, context, jkey_type, - )?; - - let key = match auth { - true => match key_type { - "avl-p" => { - let wallet = AvailWallet::::from_bytes(&key)?; - Keys::PrivateKey(wallet.private_key) - } - "avl-v" => { - let view_key = ViewKey::::from_bytes_le(&key)?; - Keys::ViewKey(view_key) - } - _ => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Invalid key type".to_string(), - "Invalid key type".to_string(), - )) - } - }, - false => { - let password = password.ok_or(AvailError::new( - AvailErrorType::Internal, - "Login".to_string(), - "Login".to_string(), - ))?; - match key_type { - "avl-p" => { - let pkey_ciphertext = Ciphertext::::from_bytes_le(&key)?; - let pkey = Encryptor::::decrypt_private_key_with_secret( - &pkey_ciphertext, - password, - )?; - - Keys::PrivateKey(pkey) - } - "avl-v" => { - let vkey_ciphertext = Ciphertext::::from_bytes_le(&key)?; - let vkey = - Encryptor::::decrypt_view_key_with_secret(&vkey_ciphertext, password)?; - - Keys::ViewKey(vkey) - } - _ => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Invalid key type".to_string(), - "Invalid key type".to_string(), - )) - } - } - } - }; - - Ok(key) -} - -///Deletes the data stored in SharedPreferences and the key in keystore. -#[tauri::command(rename_all = "snake_case")] -pub fn keystore_delete(password: Option<&str>) -> AvailResult { - let network = get_network()?; - - let _validation = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => keystore_load::(password, "avl-v")?, - }; - - let (jvm, activity) = prepare_jvm()?; - - let _env = jvm.attach_current_thread()?; - - let mut env = jvm.get_env()?; - - let class = env.find_class("com/example/keystore/KeyStoreModule")?; - - let alias = env.new_string("AV_KEYSTORE")?; - let context = unsafe { JObject::from_raw(activity as jni::sys::jobject) }; - - Java_com_example_keystore_KeyStoreModule_delete(env, class, alias, context)?; - - delete_user_encrypted_data()?; - delete_user()?; - delete_all_server_storage()?; - remove_view_session()?; - delete_user_preferences()?; - - Ok("Keystore Deleted".to_string()) -} - -/// Checks if the device supports biometric authentication using jni -#[tauri::command(rename_all = "snake_case")] -pub fn device_auth_availability() -> AvailResult { - let (jvm, activity) = prepare_jvm()?; - - jvm.attach_current_thread()?; - - let mut env = jvm.get_env()?; - - let class = env.find_class("com/example/keystore/KeyStoreModule")?; - - let context = unsafe { JObject::from_raw(activity as jni::sys::jobject) }; - - Java_com_example_keystore_KeyStoreModule_check(env, class, context) -} - -/// Checks if the app has permission to use biometric authentication -#[tauri::command(rename_all = "snake_case")] -pub fn device_auth_permission() -> AvailResult { - let (jvm, activity) = prepare_jvm()?; - - jvm.attach_current_thread()?; - - let mut env = jvm.get_env()?; - - let class = env.find_class("com/example/keystore/KeyStoreModule")?; - - let context = unsafe { JObject::from_raw(activity as jni::sys::jobject) }; - - Java_com_example_keystore_KeyStoreModule_permission(env, class, context) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::models::wallet::AvailWallet; - use avail_common::models::constants::STRONG_PASSWORD; - - #[test] - fn test_keystore_init_password() { - let wallet = AvailWallet::::new().unwrap(); - - let _result = keystore_init( - STRONG_PASSWORD, - false, - &wallet.private_key, - &wallet.view_key, - ) - .unwrap(); - } - - //Requires android environment to run - #[test] - fn test_keystore_init_biometric() { - let wallet = AvailWallet::::new().unwrap(); - - let _result = keystore_init("", true, &wallet.private_key, &wallet.view_key).unwrap(); - } - - //Requires android environment to run if not password auth - #[test] - fn test_keystore_load() { - let _result = keystore_load::(Some(STRONG_PASSWORD), "avl-p").unwrap(); - } - - //Requires android environment to run - #[test] - fn test_keystore_delete() { - let _result = keystore_delete(Some(STRONG_PASSWORD)).unwrap(); - } - - #[test] - fn test_delete_wallet() { - use crate::models::storage::persistent::PersistentStorage; - let storage = PersistentStorage::new().unwrap(); - storage.execute_query("DROP TABLE wallet").unwrap(); - } - - #[test] - fn test_vk_from_bytes() { - let v_key = [ - 208, 66, 183, 166, 111, 221, 124, 205, 251, 28, 154, 84, 205, 85, 179, 53, 10, 216, - 154, 110, 70, 94, 148, 38, 231, 248, 224, 159, 244, 81, 0, 0, - ]; - - let _hashkey = [ - 87, 43, 111, 89, 49, 111, 82, 90, 55, 120, 119, 78, 52, 82, 98, 69, 97, 55, 74, 84, - 110, 76, 116, 67, 76, 82, 82, 82, 116, 100, 115, 69, - ]; - - let _view_key = ViewKey::::from_bytes_le(&v_key).unwrap(); - } -} diff --git a/backend/src/services/account/key_management/desktop.rs b/backend/src/services/account/key_management/desktop.rs deleted file mode 100644 index bdeaaf3a..00000000 --- a/backend/src/services/account/key_management/desktop.rs +++ /dev/null @@ -1,229 +0,0 @@ -use bip39::Mnemonic; -use keyring::Entry; -use snarkvm::console::program::{FromFields, Itertools, ToFields}; -use snarkvm::prelude::{ - Ciphertext, Field, FromStr, Literal, Network, Plaintext, PrivateKey, StringType, ViewKey, -}; - -use crate::{ - helpers::validation::validate_secret_password, - models::wallet::BetterAvailWallet, - services::local_storage::utils::{ - encrypt_private_key_with_password, encrypt_view_key_with_password, - }, -}; - -use crate::models::storage::encryption::{Keys, Keys::PrivateKey as PKey, Keys::ViewKey as VKey}; -use avail_common::{ - aleo_tools::encryptor::Encryptor, - errors::{AvailError, AvailErrorType, AvailResult}, -}; - -fn encrypt_seed_phrase_with_password( - password: &str, - seed_phrase: &str, -) -> AvailResult> { - let pass_field = Field::::new_domain_separator(password); - - let seed_phrase = Plaintext::::Literal( - Literal::String(StringType::::new(seed_phrase)), - once_cell::sync::OnceCell::new(), - ); - - let cipher = seed_phrase.encrypt_symmetric(pass_field)?; - - Ok(cipher) -} - -fn decrypt_seed_phrase_with_password( - ciphertext: Ciphertext, - password: &str, -) -> AvailResult { - let pass_field = Field::::new_domain_separator(password); - let seed_phrase = ciphertext.decrypt_symmetric(pass_field)?; - - //the seed phrase string currently looks like "\"light soon prepare wire blade charge female stage ridge happy pony chief\"" - // but needs to be "light soon prepare wire blade charge female stage ridge happy pony chief" - let seed_phrase = seed_phrase.to_string().replace("\"", ""); - - Ok(seed_phrase) -} - -pub fn store(wallet: &BetterAvailWallet, password: &str) -> AvailResult { - //encrypt keys with password - if validate_secret_password(password).is_err() { - return Err(AvailError::new( - AvailErrorType::Validation, - "Invalid password".to_string(), - "Invalid password".to_string(), - )); - } - - let ciphertext_p = encrypt_private_key_with_password::(password, &wallet.private_key)?; - - let ciphertext_v = encrypt_view_key_with_password::(password, &wallet.view_key)?; - - if let Some(mnemonic) = &wallet.mnemonic { - let ciphertext_seed = encrypt_seed_phrase_with_password::(password, mnemonic.phrase())?; - //seed-phrase storage - let s_entry = Entry::new("com.avail.wallet.phrase", "avl-s")?; - let encrypted_seed_phrase = ciphertext_seed.to_string(); - s_entry.set_password(&encrypted_seed_phrase)?; - } - - //private-key storage - let p_entry = Entry::new("com.avail.wallet.p", "avl-p")?; - let encrypted_private_key = ciphertext_p.to_string(); - p_entry.set_password(&encrypted_private_key)?; - - //view-key storage - let v_entry = Entry::new("com.avail.wallet.v", "avl-v")?; - let encrypted_viewing_key = ciphertext_v.to_string(); - v_entry.set_password(&encrypted_viewing_key)?; - - Ok("Key Stored".to_string()) -} - -pub fn read_key(password: &str, key_type: &str) -> AvailResult> { - let entry = match key_type { - "avl-p" => Entry::new("com.avail.wallet.p", key_type)?, - "avl-v" => Entry::new("com.avail.wallet.v", key_type)?, - _ => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Invalid Key Type".to_string(), - "Invalid Key Type".to_string(), - )) - } - }; - let key = entry.get_password()?; - - match key_type { - "avl-p" => { - let pkey_ciphertext = Ciphertext::::from_str(&key)?; - let pkey = Encryptor::::decrypt_private_key_with_secret(&pkey_ciphertext, password)?; - - Ok(Keys::PrivateKey(pkey)) - } - "avl-v" => { - let vkey_ciphertext = Ciphertext::::from_str(&key)?; - let vkey = Encryptor::::decrypt_view_key_with_secret(&vkey_ciphertext, password)?; - - Ok(Keys::ViewKey(vkey)) - } - _ => Err(AvailError::new( - AvailErrorType::InvalidData, - "Invalid label".to_string(), - "Invalid label".to_string(), - )), - } -} - -pub fn read_seed_phrase(password: &str) -> AvailResult { - let entry = Entry::new("com.avail.wallet.phrase", "avl-s")?; - let seed_phrase = entry.get_password()?; - - let seed_phrase_ciphertext = Ciphertext::::from_str(&seed_phrase)?; - let seed_phrase = decrypt_seed_phrase_with_password::(seed_phrase_ciphertext, password)?; - - Ok(seed_phrase) -} - -pub fn delete_key(password: &str) -> AvailResult { - // verify password is correct before deletion - read_key::(password, "avl-v")?; - - let p_entry = Entry::new("com.avail.wallet.p", "avl-p")?; - p_entry.delete_password()?; - - let v_entry = Entry::new("com.avail.wallet.v", "avl-v")?; - v_entry.delete_password()?; - - Ok("Key Deleted".to_string()) -} - -#[cfg(test)] -mod windows_linux_key_management_tests { - use super::*; - use rand::thread_rng; - use snarkvm::console::network::Testnet3; - - use avail_common::models::constants::{STRONG_PASSWORD, WEAK_PASSWORD}; - - #[test] - fn test_store_strong_password() { - let mut rng = thread_rng(); - let p_key = PrivateKey::::new(&mut rng).unwrap(); - let v_key = ViewKey::::try_from(&p_key).unwrap(); - - let avail_wallet = BetterAvailWallet::::try_from(p_key).unwrap(); - - store::(&avail_wallet, STRONG_PASSWORD).unwrap(); - } - - #[test] - fn test_store_weak_password() { - let mut rng = thread_rng(); - let p_key = PrivateKey::::new(&mut rng).unwrap(); - let v_key = ViewKey::::try_from(&p_key).unwrap(); - let avail_wallet = BetterAvailWallet::::try_from(p_key.to_string()).unwrap(); - let access_type = true; - - store::(&avail_wallet, WEAK_PASSWORD).unwrap(); - } - - #[test] - fn read_key_test() { - let mut rng = thread_rng(); - let p_key = PrivateKey::::new(&mut rng).unwrap(); - let v_key = ViewKey::::try_from(&p_key).unwrap(); - let avail_wallet = BetterAvailWallet::::try_from(p_key.to_string()).unwrap(); - println!("Original Private Key: {:?}", p_key); - println!("Original Viewing Key: {:?}", v_key); - - store::(&avail_wallet, STRONG_PASSWORD).unwrap(); - - let read_p_key = read_key::(STRONG_PASSWORD, "avl-p") - .unwrap() - .is_private_key() - .unwrap(); - let read_v_key = read_key::(STRONG_PASSWORD, "avl-v") - .unwrap() - .is_view_key() - .unwrap(); - - delete_key::(STRONG_PASSWORD).unwrap(); - - println!("Fetched Private Key: {:?}", read_p_key); - println!("Fetched Viewing Key: {:?}", read_v_key); - - assert_eq!(p_key, read_p_key); - assert_eq!(v_key, read_v_key); - } - - #[test] - fn delete_key_test() { - let mut rng = thread_rng(); - let p_key = PrivateKey::::new(&mut rng).unwrap(); - let v_key = ViewKey::::try_from(&p_key).unwrap(); - let avail_wallet = BetterAvailWallet::::try_from(p_key.to_string()).unwrap(); - - store::(&avail_wallet, STRONG_PASSWORD).unwrap(); - - delete_key::(STRONG_PASSWORD).unwrap(); - } - - #[test] - fn test_encrypt_seed_phrase_with_password() { - let seed_phrase = - "light soon prepare wire blade charge female stage ridge happy pony chief"; - let password = "password"; - - let ciphertext = - encrypt_seed_phrase_with_password::(password, seed_phrase).unwrap(); - let decrypted_seed_phrase = - decrypt_seed_phrase_with_password::(ciphertext, password).unwrap(); - - assert_eq!(seed_phrase, decrypted_seed_phrase); - } -} diff --git a/backend/src/services/account/key_management/iOS.rs b/backend/src/services/account/key_management/iOS.rs deleted file mode 100644 index 7f719a7b..00000000 --- a/backend/src/services/account/key_management/iOS.rs +++ /dev/null @@ -1,244 +0,0 @@ -use snarkvm::prelude::*; -#[cfg(any(target_os = "macos", target_os = "ios"))] -use tid::{LAContext, LAPolicy}; - -#[cfg(any(target_os = "macos", target_os = "ios"))] -use security_framework::passwords::{self}; - -use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; - -///Accepts a private key and attempts to store it on the user's iOS device. -///Using apple's security framework we set access controls to protect the key entry. -///If biometrics are available we only add the SecAccessControl to the query. -#[cfg(any(target_os = "ios"))] -pub fn store_key_local( - key: &[u8], - password: &str, - access_type: bool, - key_type: bool, -) -> AvailResult<()> { - //check if user has biometry enabled - let mut ctx = LAContext::new(); - - let label = match key_type { - true => "avl-p", - false => "avl-v", - }; - - let account = match key_type { - true => "avail-user-private", - false => "avail-user-view", - }; - - let mut options = passwords_options::PasswordOptions::new_generic_password( - "com.avail.wallet", - account, - label, - ); - - let auth_control; - - if access_type { - //Change to BIOMETRY_CURRENT_SET (so new biometric sigs don't pass auth) - auth_control = passwords_options::AccessControlOptions::BIOMETRY_ANY; - } else { - auth_control = passwords_options::AccessControlOptions::APPLICATION_PASSWORD; - - ctx.set_credential(password); - - options.query.push(( - unsafe { CFString::wrap_under_get_rule(kSecUseAuthenticationContext) }, - unsafe { CFType::wrap_under_create_rule(ctx.into_ref()) }, - )); - } - - options.set_access_control_options(auth_control); - - passwords::set_password_internal(&mut options, key)?; - - Ok(()) -} - -/// stores both the private key and viewing key inside the keychain -#[cfg(any(target_os = "ios"))] -pub fn store_keys_local( - password: &str, - access_type: bool, - p_key: &PrivateKey, - v_key: &ViewKey, -) -> AvailResult { - store_key_local(&p_key.to_bytes_le()?, password, access_type, true)?; - store_key_local(&v_key.to_bytes_le()?, password, access_type, false)?; - - Ok("Key Stored".to_string()) -} - -#[cfg(any(target_os = "ios"))] -/// Accepts user's password if using applicaiton password to authenticate -/// We construct a CFDictionary query to search for the key entry in the keychain. -/// using SecItemCopyMatching we attempt to retrieve the key entry from the keychain. -/// and pass in the context to SecItemCopyMatching. -/// If using biometrics we just pass in the SecAccessControl to the query but then this is blocking (seperate method). -pub fn search(password: Option<&str>, label: &str) -> AvailResult> { - let auth = get_auth_type()?; - - let account = try_label_to_account_str(label)?; - - let context = if auth { - None - } else { - password.map(|password| { - let mut ctx = LAContext::new(); - ctx.set_credential(password); - ctx.into_ref() as *const libc::c_void - }) - }; - - let key = get_generic_password("com.avail", &account, auth, context, label)?; - - match label { - "avl-p" => { - let wallet = AvailWallet::::from_bytes(&key)?; - - Ok(Keys::PrivateKey(wallet.private_key)) - } - "avl-v" => { - let viewing_key = ViewKey::::from_bytes_le(&key)?; - - Ok(Keys::ViewKey(viewing_key)) - } - _ => Err(AvailError::new( - AvailErrorType::InvalidData, - "Invalid label".to_string(), - "Invalid label".to_string(), - )), - } -} - -/* --Production-- */ -/* -#[cfg(any(target_os = "macos", target_os = "ios"))] -#[tauri::command(rename_all = "snake_case")] -pub fn delete_ios(password: Option<&str>) -> AvailResult { - let network = get_network()?; - // verify password is correct before deletion - let _validation = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => search::(password, "avl-v")?, - }; - - match passwords::delete_generic_password("com.avail", "avail-user-view", "avl-v") { - Ok(_) => (), - Err(e) => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Viewing key not found locally".to_string(), - format!("{:?}", e), - )) - } - }; - - match passwords::delete_generic_password("com.avail", "avail-user-private", "avl-p") { - Ok(_) => (), - Err(e) => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Private key not found locally".to_string(), - format!("{:?}", e), - )) - } - }; - - delete_user_encrypted_data()?; - delete_user()?; - delete_all_server_storage()?; - remove_view_session()?; - delete_user_preferences()?; - - Ok("Wallet Deleted".to_string()) -} -*/ - -// TODO - This should only delete key, user deletion should be a separate function call -/* --Testing-- */ -#[tauri::command(rename_all = "snake_case")] -pub async fn delete_ios(_password: Option<&str>) -> AvailResult { - match passwords::delete_generic_password("com.avail", "avail-user-view", "avl-v") { - Ok(_) => (), - Err(e) => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Viewing key not found locally".to_string(), - format!("{:?}", e), - )) - } - }; - - match passwords::delete_generic_password("com.avail", "avail-user-private", "avl-p") { - Ok(_) => (), - Err(e) => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Private key not found locally".to_string(), - format!("{:?}", e), - )) - } - }; - Ok("Key Deleted".to_string()) -} - -/// Checks if the user's device has biometrics enabled. -#[tauri::command(rename_all = "snake_case")] -#[cfg(any(target_os = "macos", target_os = "ios"))] -pub fn prepare_context() -> bool { - let ctx = LAContext::new(); - ctx.can_evaluate_policy(LAPolicy::DeviceOwnerAuthenticationWithBiometrics) -} - -#[cfg(any(target_os = "ios"))] -//issues with entitlement signing on mac (see way to run all tests for mac with entitlement added) -#[cfg(test)] -mod tests { - use super::*; - use avail_common::models::constants::STRONG_PASSWORD; - use snarkvm::prelude::{PrivateKey, Testnet3}; - - #[test] - fn test_store_key_local_password() { - let pk = PrivateKey::::new(&mut rand::thread_rng()).unwrap(); - let seed = pk.to_bytes_le().unwrap(); - let password = STRONG_PASSWORD.to_string(); - - store_key_local(&seed, &password, false, true).unwrap(); - } - - #[test] - fn test_store_key_local_biometrics() { - let pk = PrivateKey::::new(&mut rand::thread_rng()).unwrap(); - let seed = pk.to_bytes_le().unwrap(); - - store_key_local(&seed, "", true, true).unwrap(); - } - - #[test] - fn test_context_set_credential() { - let mut ctx = LAContext::new(); - ctx.set_credential(STRONG_PASSWORD); - - let _cf = unsafe { CFType::wrap_under_get_rule(ctx.into_ref()) }; - } - - #[test] - fn test_search_password() { - search::(Some(STRONG_PASSWORD), "avl-p").unwrap(); - } - - #[test] - fn test_search_biometrics() { - search::(None, "avl-p").unwrap(); - } - - #[tokio::test] - async fn delete_key() { - delete_ios(None).await.unwrap(); - } -} diff --git a/backend/src/services/account/key_management/key_controller.rs b/backend/src/services/account/key_management/key_controller.rs deleted file mode 100644 index b485205d..00000000 --- a/backend/src/services/account/key_management/key_controller.rs +++ /dev/null @@ -1,207 +0,0 @@ -use crate::models::{storage::encryption::Keys, wallet::BetterAvailWallet}; -use crate::services::local_storage::session::password::PASS; - -#[cfg(target_os = "android")] -use super::android::{keystore_delete, keystore_init, keystore_load}; - -#[cfg(any(target_os = "ios"))] -use super::ios::{delete_ios, search, store_keys_local}; - -use snarkvm::prelude::{Identifier, Network, PrivateKey, ViewKey}; - -use super::desktop::{delete_key, read_key, read_seed_phrase, store}; -use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; - -/// This trait is used as a standard interface for the key management service. -/// The key_type field refers to the private key type when true and the viewing key type when false. -pub trait KeyController { - fn store_key(&self, password: &str, wallet: &BetterAvailWallet) -> AvailResult; - - fn delete_key(&self, password: Option<&str>, ext: Identifier) -> AvailResult; - fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult>; - fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult; -} - -pub struct AndroidKeyController; - -#[cfg(target_os = "android")] -impl KeyController for AndroidKeyController { - fn store_key(&self, password: &str, wallet: BetterAvailWallet) -> AvailResult { - keystore_init(password, access_type, p_key, v_key) - } - - fn import_key( - &self, - password: &str, - p_key: &PrivateKey, - v_key: &ViewKey, - ) -> AvailResult { - keystore_init(password, access_type, p_key, v_key) - } - - //TODO authenticate using read_key - fn delete_key(&self, password: Option<&str>, ext: Identifier) -> AvailResult { - keystore_delete(password) - } - - fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult> { - keystore_load(password, key_type) - } - - fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult { - read_seed_phrase::(password) - } -} - -pub struct iOSKeyController; - -#[cfg(target_os = "ios")] -impl KeyController for iOSKeyController { - fn store_key(&self, password: &str, wallet: BetterAvailWallet) -> AvailResult { - store_keys_local(password, access_type, p_key, v_key) - } - - fn import_key( - &self, - password: &str, - access_type: bool, - p_key: &PrivateKey, - v_key: &ViewKey, - ) -> AvailResult { - store_keys_local(password, access_type, p_key, v_key) - } - - //TODO authenticate using read_key - fn delete_key(&self, password: Option<&str>, ext: Identifier) -> AvailResult { - delete_ios(password) - } - - fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult> { - search(password, key_type) - } - - fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult { - read_seed_phrase(password, ext) - } -} - -pub struct macKeyController; - -#[cfg(target_os = "macos")] -impl KeyController for macKeyController { - fn store_key(&self, password: &str, wallet: &BetterAvailWallet) -> AvailResult { - store(wallet, password) - } - - fn delete_key(&self, password: Option<&str>, _ext: Identifier) -> AvailResult { - match password { - Some(password) => delete_key::(password), - None => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Password is required".to_string(), - "Password is required".to_string(), - )) - } - } - } - - fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult> { - match password { - Some(password) => read_key(password, key_type), - None => { - let password = match PASS.get_instance() { - Ok(password) => password, - Err(e) => return Err(e), - }; - - read_key(&password, key_type) - } - } - } - - fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult { - read_seed_phrase::(password) - } -} - -pub struct linuxKeyController; - -impl KeyController for linuxKeyController { - fn store_key(&self, password: &str, wallet: &BetterAvailWallet) -> AvailResult { - store(wallet, password) - } - - //TODO authenticate using read_key - fn delete_key(&self, password: Option<&str>, _ext: Identifier) -> AvailResult { - match password { - Some(password) => delete_key::(password), - None => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Password is required".to_string(), - "Password is required".to_string(), - )) - } - } - } - - fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult> { - match password { - Some(password) => read_key(password, key_type), - None => { - let password = match PASS.get_instance() { - Ok(password) => password, - Err(e) => return Err(e), - }; - - read_key(&password, key_type) - } - } - } - - fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult { - read_seed_phrase::(password) - } -} - -pub struct windowsKeyController; - -#[cfg(target_os = "windows")] -impl KeyController for windowsKeyController { - fn store_key(&self, password: &str, wallet: &BetterAvailWallet) -> AvailResult { - store(wallet, password) - } - - //TODO authenticate using read_key - fn delete_key(&self, password: Option<&str>, ext: Identifier) -> AvailResult { - match password { - Some(password) => delete_key::(password), - None => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Password is required".to_string(), - "Password is required".to_string(), - )) - } - } - } - - fn read_key(&self, password: Option<&str>, key_type: &str) -> AvailResult> { - match password { - Some(password) => read_key(password, key_type), - None => { - let password = match PASS.get_instance() { - Ok(password) => password, - Err(e) => return Err(e), - }; - - read_key(&password, key_type) - } - } - } - - fn read_phrase(&self, password: &str, ext: Identifier) -> AvailResult { - read_seed_phrase::(password) - } -} diff --git a/backend/src/services/account/phrase_recovery.rs b/backend/src/services/account/phrase_recovery.rs deleted file mode 100644 index 29b54b4d..00000000 --- a/backend/src/services/account/phrase_recovery.rs +++ /dev/null @@ -1,96 +0,0 @@ -use snarkvm::prelude::{Testnet3, ToBytes}; - -use crate::{ - models::storage::languages::Languages, - services::local_storage::{ - encrypted_data::initialize_encrypted_data_table, - persistent_storage::initial_user_preferences, session::view::VIEWSESSION, - }, -}; - -use avail_common::errors::AvailResult; - -use crate::api::user::{create_user, get_user}; -use crate::models::wallet::BetterAvailWallet; -use crate::services::account::key_management::key_controller::{ - linuxKeyController, macKeyController, windowsKeyController, KeyController, -}; -use crate::services::authentication::session::get_session_after_creation; -use crate::services::local_storage::{ - encrypted_data::get_and_store_all_data, tokens::init_tokens_table, -}; -use avail_common::models::user::User; - -#[tauri::command(rename_all = "snake_case")] -/// This function provides the tauri bindings to recover an avail wallet from a seed phrase. -pub async fn recover_wallet_from_seed_phrase( - seed_phrase: &str, - password: &str, - access_type: bool, - language: Languages, -) -> AvailResult<()> { - let avail_wallet = BetterAvailWallet::::from_seed_phrase( - seed_phrase, - Languages::to_bip39_language(&language), - )?; - - let key_manager = { - #[cfg(target_os = "macos")] - { - macKeyController - } - #[cfg(target_os = "windows")] - { - windowsKeyController - } - #[cfg(target_os = "linux")] - { - linuxKeyController - } - }; - - key_manager.store_key(password, &avail_wallet)?; - - get_session_after_creation::(&avail_wallet.private_key).await?; - - let (username, tag, backup) = match get_user().await { - Ok(user) => (user.username, user.tag, user.backup), - Err(_) => { - let request = User { - username: None, - address: avail_wallet.get_address(), - tag: None, - backup: false, - }; - create_user(request).await?; - (None, None, false) - } - }; - - let _v_key = avail_wallet.view_key.to_bytes_le()?; - - initial_user_preferences( - access_type, - username, - tag, - true, - backup, - avail_wallet.get_address(), - language, - )?; - - init_tokens_table()?; - - // some function - - initialize_encrypted_data_table()?; - VIEWSESSION - .set_view_session(&avail_wallet.get_view_key()) - .unwrap(); - - if backup { - get_and_store_all_data().await?; - } - - Ok(()) -} diff --git a/backend/src/services/account/shard_recovery.rs b/backend/src/services/account/shard_recovery.rs deleted file mode 100644 index 8b137891..00000000 --- a/backend/src/services/account/shard_recovery.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/backend/src/services/account/utils.rs b/backend/src/services/account/utils.rs deleted file mode 100644 index 8204c7c2..00000000 --- a/backend/src/services/account/utils.rs +++ /dev/null @@ -1,76 +0,0 @@ -use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; -use rand::Rng; -use std::process::Command; - -pub fn generate_discriminant() -> u32 { - let mut rng = rand::thread_rng(); - let mut discriminant: u32 = 0; - for _ in 0..4 { - discriminant = discriminant * 10 + rng.gen_range(0..10); - } - discriminant -} - -#[tauri::command(rename_all = "snake_case")] -pub fn open_url(url: &str) -> AvailResult<()> { - #[cfg(target_os = "windows")] - match Command::new("cmd").args(&["/c", "start", url]).spawn() { - Ok(_) => return Ok(()), - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - format!("Error opening url: {}", e), - "Error opening url".to_string(), - )) - } - }; - - #[cfg(target_os = "macos")] - match Command::new("open").arg(url).spawn() { - Ok(_) => return Ok(()), - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - format!("Error opening url: {}", e), - "Error opening url".to_string(), - )) - } - }; - - #[cfg(target_os = "linux")] - match Command::new("xdg-open").arg(url).spawn() { - Ok(_) => return Ok(()), - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - format!("Error opening url: {}", e), - "Error opening url".to_string(), - )) - } - }; -} - -#[tauri::command(rename_all = "snake_case")] -pub fn os_type() -> AvailResult { - #[cfg(target_os = "windows")] - return Ok("windows".to_string()); - - #[cfg(target_os = "macos")] - return Ok("macos".to_string()); - - #[cfg(target_os = "linux")] - return Ok("linux".to_string()); -} - -#[test] -fn test_generate_discriminant() { - let discriminant = generate_discriminant(); - print!("discriminant: {}", discriminant); - assert!(discriminant > 999 && discriminant < 10000); -} - -#[test] -fn test_open_url() { - let result = open_url("https://discord.gg/A6N5X2yX"); - assert!(result.is_ok()); -} diff --git a/backend/src/services/authentication.rs b/backend/src/services/authentication.rs deleted file mode 100644 index 3c452ed3..00000000 --- a/backend/src/services/authentication.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod session; - -#[cfg(any(target_os = "ios"))] -pub mod ios; - -#[cfg(target_os = "android")] -pub mod android; diff --git a/backend/src/services/authentication/android.rs b/backend/src/services/authentication/android.rs deleted file mode 100644 index 799ec6c2..00000000 --- a/backend/src/services/authentication/android.rs +++ /dev/null @@ -1,39 +0,0 @@ -use snarkvm::prelude::{Testnet3, ToBytes}; -use std::str::FromStr; - -use crate::{ - models::storage::encryption::Keys, - services::{ - account::key_management::android::keystore_load, - local_storage::persistent_storage::{get_network, store_view_session}, - }, -}; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::network::SupportedNetworks, -}; - -#[tauri::command(rename_all = "snake_case")] -pub fn android_auth(password: Option<&str>, _key_type: &str) -> AvailResult<()> { - let network = get_network()?; - - let result = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => keystore_load::(password, "avl-v")?, - }; - - let view_key_bytes = match result { - Keys::ViewKey(key) => key.to_bytes_le()?, - Keys::PrivateKey(_) => { - return Err(AvailError::new( - AvailErrorType::InvalidData, - "Invalid Key Type".to_string(), - "Invalid Key Type".to_string(), - )) - } - }; - - store_view_session(view_key_bytes)?; - - Ok(()) -} diff --git a/backend/src/services/authentication/ios.rs b/backend/src/services/authentication/ios.rs deleted file mode 100644 index aa3cf432..00000000 --- a/backend/src/services/authentication/ios.rs +++ /dev/null @@ -1,37 +0,0 @@ -use snarkvm::prelude::{Testnet3, ToBytes}; -use std::str::FromStr; - -use avail_common::models::network::SupportedNetworks; - -use crate::services::local_storage::{persistent_storage::get_network, session::view::VIEWSESSION}; - -#[cfg(any(target_os = "ios"))] -use crate::{models::storage::encryption::Keys, services::account::key_management::ios::search}; - -use avail_common::errors::{AvError, AvailErrorType, AvailResult}; - -#[cfg(any(target_os = "ios"))] -#[tauri::command(rename_all = "snake_case")] -pub fn ios_auth(password: Option<&str>, key_type: &str) -> AvailResult<()> { - let network = get_network()?; - - let key = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => search::(password, key_type)?, - _ => search::(password, key_type)?, - }; - - let view_key_bytes = match key { - Keys::ViewKey(key) => key.to_bytes_le()?, - _ => { - return Err(AvError::new( - AvailErrorType::InvalidData, - "Invalid Key Type".to_string(), - "Invalid Key Type".to_string(), - )) - } - }; - - //TODO - Store view key session - - Ok(()) -} diff --git a/backend/src/services/authentication/session.rs b/backend/src/services/authentication/session.rs deleted file mode 100644 index 0703580f..00000000 --- a/backend/src/services/authentication/session.rs +++ /dev/null @@ -1,327 +0,0 @@ -use crate::api::client::SESSION; -use crate::helpers::utils::HOST; -use crate::models::auth::{CreateSessionRequest, VerifySessionResponse}; -use crate::services::local_storage::{ - persistent_storage::{get_address_string, get_network}, - session::password::PASS, - utils::{sign_message, sign_message_w_key}, -}; -use snarkvm::prelude::*; -use tauri_plugin_http::reqwest; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::{ - network::SupportedNetworks, - server_auth::{self, VerifySessionRequest}, - }, -}; - -/// Authenticates user both locally and on server. -#[tauri::command(rename_all = "snake_case")] -pub async fn get_session(password: Option) -> AvailResult { - let address = get_address_string()?; - let session_request = request_hash(&address).await?; - - let network = get_network()?; - - let (sig, _) = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - sign_message::(&session_request.hash, password.clone())? - } - _ => sign_message::(&session_request.hash, password.clone())?, - }; - - let verify_request = server_auth::VerifySessionRequest { - signature: sig.to_string(), - session_id: session_request.session_id, - }; - - let api = env!("API"); - - let client = reqwest::Client::new(); - - let res = client - .post(format!("{}/auth/login/", api)) - .json(&verify_request) - .send() - .await?; - - if res.status() == 200 { - let cookie = res.cookies().next(); - - let session_cookie = match cookie { - Some(cookie) => cookie, - None => { - return Err(AvailError::new( - AvailErrorType::Validation, - "Session cookie not found in auth response".to_string(), - "Session cookie not found in auth response".to_string(), - )) - } - }; - - SESSION.set_session_token(session_cookie.value().to_string()); - - let _pass_session = match password { - Some(password) => PASS.set_pass_session(&password)?, - None => {} - }; - - Ok(session_request.session_id.to_string()) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Invalid Signature".to_string(), - "Invalid Signature".to_string(), - )) - } -} - -pub async fn get_session_after_creation( - private_key: &PrivateKey, -) -> AvailResult { - let address = Address::::try_from(private_key)?; - let session_request = request_hash(&address.to_string()).await?; - - let (sig, _) = sign_message_w_key::(&session_request.hash, private_key)?; - - let verify_request = server_auth::VerifySessionRequest { - signature: sig.to_string(), - session_id: session_request.session_id, - }; - - let api = env!("API"); - - let res = reqwest::Client::new() - .post(format!("{}/auth/login/", api)) - .json(&verify_request) - .send() - .await?; - - if res.status() == 200 { - let cookie = res.cookies().next(); - - let session_cookie = match cookie { - Some(cookie) => cookie, - None => { - return Err(AvailError::new( - AvailErrorType::Validation, - "Session cookie not found in auth response".to_string(), - "Session cookie not found in auth response".to_string(), - )) - } - }; - - SESSION.set_session_token(session_cookie.value().to_string()); - - Ok(session_request.session_id.to_string()) - } else { - if res.status() == 0 { - return Err(AvailError::new( - AvailErrorType::Network, - "No internet connection".to_string(), - "No internet connection".to_string(), - )); - } - - Err(AvailError::new( - AvailErrorType::External, - "Invalid Signature".to_string(), - "Invalid Signature".to_string(), - )) - } -} - -/// requests the initial hash to sign from server -/// Function 1 -pub async fn request_hash(address: &str) -> AvailResult { - let client = reqwest::Client::new(); - - let request = server_auth::CreateSessionRequest { - public_key: address.to_owned(), - }; - - let api = env!("API"); - - let res = client - .post(format!("{}/auth/request/", api)) - .header("Content-Type", "application/json") - .json(&request) - .send() - .await?; - - if res.status() == 201 { - Ok(res.json::().await?) - } else { - if res.status() == 0 { - return Err(AvailError::new( - AvailErrorType::Network, - "No internet connection".to_string(), - "No internet connection".to_string(), - )); - } - - Err(AvailError::new( - AvailErrorType::External, - "Error requesting auth token.".to_string(), - "Error requesting auth token.".to_string(), - )) - } -} - -/* -- Not used -- */ - -///Function 2 -pub fn sign_hash( - request: CreateSessionRequest, - password: Option, -) -> AvailResult { - let network = get_network()?; - - let (sig, _) = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => sign_message::(&request.hash, password)?, - _ => sign_message::(&request.hash, password)?, - }; - - let verify_request = server_auth::VerifySessionRequest { - signature: sig.to_string(), - session_id: request.to_response().session_id, - }; - - Ok(verify_request) -} - -///Function 3 -pub async fn get_session_only(request: VerifySessionResponse) -> AvailResult { - let client = reqwest::Client::new(); - - let res = client - .post("https://test-api.avail.global/auth/login/") - .json(&request.to_request()) - .send() - .await?; - - if res.status() == 200 { - res.json::().await?; - // store session id in local storage (cookies) - Ok(request.session_id.to_string()) - } else { - Err(AvailError::new( - AvailErrorType::External, - "Invalid Signature".to_string(), - "Invalid Signature".to_string(), - )) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - use crate::api::encrypted_data::get_new_transaction_messages; - use crate::api::user::create_user; - use crate::models::storage::languages::Languages; - use crate::models::wallet::BetterAvailWallet; - use crate::services::account::key_management::desktop::{delete_key, store}; - use crate::services::account::utils::generate_discriminant; - use crate::services::local_storage::encrypted_data::delete_user_encrypted_data; - use crate::services::local_storage::persistent_storage::{ - delete_user_preferences, initial_user_preferences, - }; - use crate::services::local_storage::session::view::VIEWSESSION; - use avail_common::models::constants::{STRONG_PASSWORD, TESTNET_PRIVATE_KEY}; - use avail_common::models::user::User; - use snarkvm::prelude::Testnet3; - - use avail_common::converters::messages::{field_to_fields, utf8_string_to_bits}; - - #[tokio::test] - async fn test_setup_prerequisites() { - match delete_key::(STRONG_PASSWORD) { - Ok(_) => println!("Key Deleted"), - Err(_) => println!("No key found"), - } - - // delete_user().await.unwrap(); - delete_user_encrypted_data().unwrap(); - delete_user_preferences().unwrap(); - - let p_key = PrivateKey::::new(&mut rand::thread_rng()).unwrap(); - let wallet = BetterAvailWallet::::try_from(p_key.to_string()).unwrap(); - - let v_key = ViewKey::::try_from(&p_key).unwrap(); - - let tag = generate_discriminant(); - - initial_user_preferences( - false, - Some("Karp".to_string()), - Some(tag), - false, - false, - v_key.to_address().to_string(), - Languages::English, - ) - .unwrap(); - - VIEWSESSION.set_view_session(&v_key.to_string()).unwrap(); - - let user_request = User { - address: v_key.to_address().to_string(), - username: Some("Karp".to_string()), - tag: Some(tag), - backup: false, - }; - - create_user(user_request).await.unwrap(); - - store::(&wallet, STRONG_PASSWORD).unwrap(); - } - - #[tokio::test] - async fn test_get_session_password() { - //let username = get_username().unwrap(); - // test_setup_prerequisites(); - let session = get_session(Some(STRONG_PASSWORD.to_string())) - .await - .unwrap(); - print!("{}", session); - - get_new_transaction_messages::().await.unwrap(); - - println!("Successful fetch"); - - //let address =name_to_address::(&username).await.unwrap(); - //let user = get_user().await.unwrap(); - } - - #[tokio::test] - async fn test_request_hash() { - let address = get_address_string().unwrap(); - - let hash = request_hash(&address).await; - print!("{}", hash.unwrap().hash); - // assert!(hash.is_ok()); - } - - #[test] - fn test_sign_hash() { - let sig = { - let key = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - - //get private key from local storage - - let rng = &mut rand::thread_rng(); - - let msg = utf8_string_to_bits("KEqj6BDUl0Nh0izyOsXuW916qSoGxtfE"); - let msg_field = Testnet3::hash_bhp512(&msg).unwrap(); - let msg = field_to_fields(&msg_field).unwrap(); - - key.sign(&msg, rng).unwrap() - }; - - print!("{}", sig.to_string()); - } -} diff --git a/backend/src/services/local_storage.rs b/backend/src/services/local_storage.rs deleted file mode 100644 index c23e04c0..00000000 --- a/backend/src/services/local_storage.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod encrypted_data; -pub mod persistent_storage; -pub mod session; -pub mod storage_api; -pub mod tokens; -pub mod utils; diff --git a/backend/src/services/local_storage/encrypted_data.rs b/backend/src/services/local_storage/encrypted_data.rs deleted file mode 100644 index eb2f70fc..00000000 --- a/backend/src/services/local_storage/encrypted_data.rs +++ /dev/null @@ -1,794 +0,0 @@ -use std::str::FromStr; - -use chrono::{DateTime, Utc}; -use rusqlite::{params_from_iter, ToSql}; -use snarkvm::prelude::{Network, Testnet3}; - -use crate::models::pointers::{ - deployment::DeploymentPointer, record::AvailRecord, transaction::TransactionPointer, - transition::TransitionPointer, -}; -use crate::models::storage::persistent::PersistentStorage; -use crate::{ - api::encrypted_data::recover_data, - services::local_storage::{persistent_storage::*, session::view::VIEWSESSION}, -}; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::encrypted_data::{ - EncryptedData, EncryptedDataTypeCommon, EventTypeCommon, RecordTypeCommon, TransactionState, - }, - models::network::SupportedNetworks, -}; - -/* Main Encrypted Data funcions */ - -///initialize enrypted data table -pub fn initialize_encrypted_data_table() -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - storage.execute_query( - "CREATE TABLE IF NOT EXISTS encrypted_data ( - id TEXT PRIMARY KEY, - owner TEXT NOT NULL, - ciphertext TEXT NOT NULL, - nonce TEXT NOT NULL, - flavour TEXT NOT NULL, - record_type TEXT, - program_ids TEXT, - function_ids TEXT, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP, - synced_on TIMESTAMP, - network TEXT NOT NULL, - record_name TEXT, - spent BOOLEAN, - event_type TEXT, - record_nonce TEXT, - state TEXT - )", - )?; - - Ok(()) -} - -/// store any encrypted data in persistent storage -pub fn store_encrypted_data(data: EncryptedData) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - let id = match data.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found.".to_string(), - "No id found.".to_string(), - ))?, - }; - - let flavour = data.flavour.to_str(); - let ciphertext = data.ciphertext; - let nonce = data.nonce; - let record_type = match data.record_type { - Some(record_type) => Some(record_type.to_str()), - None => None, - }; - let event_type = match data.event_type { - Some(event_type) => Some(event_type.to_str()), - None => None, - }; - let transaction_state = match data.transaction_state { - Some(transaction_state) => Some(transaction_state.to_str()), - None => None, - }; - - storage.save_mixed( - vec![&id,&data.owner, &ciphertext, &nonce, &flavour,&record_type,&data.program_ids,&data.function_ids,&data.created_at,&data.updated_at,&data.synced_on,&data.network,&data.record_name,&data.spent,&event_type,&data.record_nonce,&transaction_state], - "INSERT INTO encrypted_data (id,owner,ciphertext,nonce,flavour,record_type,program_ids,function_ids,created_at,updated_at,synced_on,network,record_name,spent,event_type,record_nonce,state) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17)" - .to_string(), - )?; - - Ok(()) -} - -pub fn handle_encrypted_data_query(query: &str) -> AvailResult> { - let storage = PersistentStorage::new()?; - - let mut query_statement = storage.conn.prepare(query)?; - - let query_iter = query_statement.query_map([], |row| { - let id: String = row.get(0)?; - let owner: String = row.get(1)?; - let ciphertext: String = row.get(2)?; - let nonce: String = row.get(3)?; - let flavour: String = row.get(4)?; - let record_type: Option = row.get(5)?; - let program_ids: Option = row.get(6)?; - let function_ids: Option = row.get(7)?; - let created_at: DateTime = row.get(8)?; - let updated_at: Option> = row.get(9)?; - let synced_on: Option> = row.get(10)?; - let network: String = row.get(11)?; - let record_name: Option = row.get(12)?; - let spent: Option = row.get(13)?; - let event_type: Option = row.get(14)?; - let record_nonce: Option = row.get(15)?; - let transaction_state: Option = row.get(16)?; - - let id = match uuid::Uuid::parse_str(&id) { - Ok(id) => id, - Err(_) => { - return Err(rusqlite::Error::InvalidColumnType( - 0, - "Error converting id string to uuid".to_string(), - rusqlite::types::Type::Text, - )) - } - }; - - let record_type = match record_type { - Some(record_type) => RecordTypeCommon::from_str(&record_type), - None => None, - }; - - let event_type = match event_type { - Some(event_type) => EventTypeCommon::from_str(&event_type), - None => None, - }; - - let transaction_state = match transaction_state { - Some(transaction_state) => TransactionState::from_str(&transaction_state), - None => None, - }; - - let flavour = EncryptedDataTypeCommon::from(flavour.as_str()); - - let encrypted_data = EncryptedData::new( - Some(id), - owner, - ciphertext, - nonce, - flavour, - record_type, - program_ids, - function_ids, - created_at, - updated_at, - synced_on, - network, - record_name, - spent, - event_type, - record_nonce, - transaction_state, - ); - - Ok(encrypted_data) - })?; - - let mut encrypted_data: Vec = Vec::new(); - - for data in query_iter { - encrypted_data.push(data?); - } - - Ok(encrypted_data) -} - -pub fn handle_encrypted_data_query_params( - query: &str, - query_params: Vec, -) -> AvailResult> { - let storage = PersistentStorage::new()?; - - let mut query_statement = storage.conn.prepare(query)?; - - let query_iter = query_statement.query_map(params_from_iter(query_params.iter()), |row| { - let id: String = row.get(0)?; - let owner: String = row.get(1)?; - let ciphertext: String = row.get(2)?; - let nonce: String = row.get(3)?; - let flavour: String = row.get(4)?; - let record_type: Option = row.get(5)?; - let program_ids: Option = row.get(6)?; - let function_ids: Option = row.get(7)?; - let created_at: DateTime = row.get(8)?; - let updated_at: Option> = row.get(9)?; - let synced_on: Option> = row.get(10)?; - let network: String = row.get(11)?; - let record_name: Option = row.get(12)?; - let spent: Option = row.get(13)?; - let event_type: Option = row.get(14)?; - let record_nonce: Option = row.get(15)?; - let transaction_state: Option = row.get(16)?; - - let id = match uuid::Uuid::parse_str(&id) { - Ok(id) => id, - Err(_) => { - return Err(rusqlite::Error::InvalidColumnType( - 0, - "Error converting id string to uuid".to_string(), - rusqlite::types::Type::Text, - )) - } - }; - - let record_type = match record_type { - Some(record_type) => RecordTypeCommon::from_str(&record_type), - None => None, - }; - - let event_type = match event_type { - Some(event_type) => EventTypeCommon::from_str(&event_type), - None => None, - }; - - let transaction_state = match transaction_state { - Some(transaction_state) => TransactionState::from_str(&transaction_state), - None => None, - }; - let flavour = EncryptedDataTypeCommon::from(flavour.as_str()); - - let encrypted_data = EncryptedData::new( - Some(id), - owner, - ciphertext, - nonce, - flavour, - record_type, - program_ids, - function_ids, - created_at, - updated_at, - synced_on, - network, - record_name, - spent, - event_type, - record_nonce, - transaction_state, - ); - - Ok(encrypted_data) - })?; - - let mut encrypted_data: Vec = Vec::new(); - - for data in query_iter { - encrypted_data.push(data?); - } - - Ok(encrypted_data) -} - -/// get encrypted data by their flavour -pub fn get_encrypted_data_by_flavour( - flavour: EncryptedDataTypeCommon, -) -> AvailResult> { - let address = get_address_string()?; - let network = get_network()?; - - let query = format!( - "SELECT * FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", - flavour.to_str(), - address, - network - ); - - handle_encrypted_data_query(&query) -} - -/// get encrypted data by id -pub fn get_encrypted_data_by_id(id: &str) -> AvailResult { - let query = format!("SELECT * FROM encrypted_data WHERE id='{}'", id); - - let encrypted_data = handle_encrypted_data_query(&query)?; - - if encrypted_data.len() > 0 { - Ok(encrypted_data[0].clone()) - } else { - Err(AvailError::new( - AvailErrorType::Internal, - "Data Not Found".to_string(), - "Data Not Found".to_string(), - )) - } -} - -/// get encrypted record pointer by nonce -pub fn get_encrypted_data_by_nonce(nonce: &str) -> AvailResult> { - let address = get_address_string()?; - let network = get_network()?; - - let query = format!( - "SELECT * FROM encrypted_data WHERE record_nonce='{}' AND owner='{}' AND network='{}'", - nonce, address, network - ); - - let encrypted_data = handle_encrypted_data_query(&query)?; - - if !encrypted_data.is_empty() { - Ok(Some(encrypted_data[0].clone())) - } else { - Ok(None) - } -} - -/* Main Encrypted Data funcions */ - -/// update encrypted data by id -pub fn update_encrypted_data_by_id(id: &str, ciphertext: &str, nonce: &str) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - let query = format!( - "UPDATE encrypted_data SET ciphertext=?1, nonce=?2 WHERE id='{}'", - id - ); - - storage.save_mixed(vec![&ciphertext, &nonce], query)?; - - Ok(()) -} - -/// update encrypted data by id -pub fn update_encrypted_data_spent_by_id( - id: &str, - ciphertext: &str, - nonce: &str, - spent: bool, -) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - let updated_at = Utc::now(); - - let query = format!( - "UPDATE encrypted_data SET ciphertext=?1, nonce=?2, spent=?3, updated_at=?4 WHERE id='{}'", - id - ); - - storage.save_mixed(vec![&ciphertext, &nonce, &spent, &updated_at], query)?; - - Ok(()) -} - -/// update encrypted data and transaction state by id -pub fn update_encrypted_transaction_state_by_id( - id: &str, - ciphertext: &str, - nonce: &str, - transaction_state: TransactionState, -) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - let query = format!( - "UPDATE encrypted_data SET ciphertext=?1, nonce=?2, state=?3 WHERE id='{}'", - id - ); - - storage.save_mixed( - vec![&ciphertext, &nonce, &transaction_state.to_str()], - query, - )?; - - Ok(()) -} - -/// update encrypted data by id and program_ids and function_ids -pub fn update_encrypted_transaction_confirmed_by_id( - id: &str, - ciphertext: &str, - nonce: &str, - program_ids: &str, - function_ids: &str, -) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - let query = format!( - "UPDATE encrypted_data SET ciphertext=?1, nonce=?2, program_ids=?3, function_ids=?4, state=?5 WHERE id='{}'", - id - ); - - storage.save_mixed( - vec![ - &ciphertext, - &nonce, - &program_ids, - &function_ids, - &TransactionState::Confirmed.to_str(), - ], - query, - )?; - - Ok(()) -} - -/// update synced_on field of encrypted data by id (data has been synced) -pub fn update_encrypted_data_synced_on_by_id(id: &str) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - let query = format!("UPDATE encrypted_data SET synced_on=?1 WHERE id='{}'", id); - - let synced_on = Utc::now(); - - storage.save_mixed(vec![&synced_on], query)?; - - Ok(()) -} - -/// delete encrypted data by id -pub fn delete_encrypted_data_by_id(id: &str) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - let query = format!("DELETE FROM encrypted_data WHERE id='{}'", id); - - storage.execute_query(&query)?; - - Ok(()) -} - -/// delete encrypted data by owner address -pub fn delete_encrypted_data_by_address() -> AvailResult<()> { - let storage = PersistentStorage::new()?; - let address = get_address_string()?; - - let query = format!("DELETE FROM encrypted_data WHERE owner='{}'", address); - - storage.execute_query(&query)?; - - Ok(()) -} - -/// delete user encrypted data storage -pub fn delete_user_encrypted_data() -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - let query = "DELETE FROM encrypted_data"; - - match storage.execute_query(query) { - Ok(r) => r, - Err(e) => match e.error_type { - AvailErrorType::NotFound => {} - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error deleting encrypted data ".to_string(), - "".to_string(), - )) - } - }, - }; - - Ok(()) -} - -pub fn drop_encrypted_data_table() -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - let query = "DROP TABLE encrypted_data"; - - match storage.execute_query(query) { - Ok(r) => r, - Err(e) => match e.error_type { - AvailErrorType::NotFound => {} - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error dropping encrypted data table ".to_string(), - "Error deleting encrypted data table".to_string(), - )) - } - }, - }; - - Ok(()) -} - -pub fn get_encrypted_data_to_backup( - last_backup_sync: DateTime, -) -> AvailResult> { - let query = "SELECT * FROM encrypted_data WHERE created_at > ?1"; - - let encrypted_data = handle_encrypted_data_query_params(query, vec![last_backup_sync])?; - - Ok(encrypted_data) -} - -pub fn get_encrypted_data_to_update( - last_backup_sync: DateTime, -) -> AvailResult> { - let query = "SELECT * FROM encrypted_data WHERE updated_at > ?1"; - - let encrypted_data = handle_encrypted_data_query_params(query, vec![last_backup_sync])?; - - Ok(encrypted_data) -} - -/// Function to handle the deletion of encrypted data when a scan fails at a specific block height -pub fn handle_block_scan_failure(block_height: u32) -> AvailResult<()> { - let view_key = VIEWSESSION.get_instance::()?; - - // get encrypted data stored withing the last two minutes - let query = "SELECT * FROM encrypted_data WHERE created_at > ?1"; - - let encrypted_data = handle_encrypted_data_query_params( - query, - vec![Utc::now() - .checked_sub_signed(chrono::Duration::minutes(2)) - .unwrap()], - )?; - - let mut ids_to_delete: Vec = vec![]; - - for data in encrypted_data { - let encrypted_struct = data.to_enrypted_struct::()?; - - match data.flavour { - EncryptedDataTypeCommon::Record => { - let record_pointer: AvailRecord = encrypted_struct.decrypt(view_key)?; - if record_pointer.pointer.block_height == block_height { - if let Some(id) = data.id { - ids_to_delete.push(id.to_string()); - } - } - } - EncryptedDataTypeCommon::Transaction => { - let tx_pointer: TransactionPointer = encrypted_struct.decrypt(view_key)?; - if let Some(tx_height) = tx_pointer.block_height() { - if tx_height == block_height { - ids_to_delete.push(data.id.unwrap().to_string()); - } - } - } - EncryptedDataTypeCommon::Deployment => { - let deployment: DeploymentPointer = encrypted_struct.decrypt(view_key)?; - - if let Some(deployment_height) = deployment.block_height { - if deployment_height == block_height { - ids_to_delete.push(data.id.unwrap().to_string()); - } - } - } - EncryptedDataTypeCommon::Transition => { - let transition: TransitionPointer = encrypted_struct.decrypt(view_key)?; - - if transition.block_height == block_height { - ids_to_delete.push(data.id.unwrap().to_string()); - } - } - _ => {} - } - } - - Ok(()) -} - -///get encrypted data and store directly locally encrypted -#[tauri::command(rename_all = "snake_case")] -pub async fn get_and_store_all_data() -> AvailResult { - let address = get_address_string()?; - let network = get_network()?; - - let data = recover_data(&address.to_string()).await?; - - for encrypted_record_pointer in data.record_pointers { - let e_r = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - AvailRecord::::to_encrypted_data_from_record(encrypted_record_pointer)? - } - _ => AvailRecord::::to_encrypted_data_from_record(encrypted_record_pointer)?, - }; - store_encrypted_data(e_r)?; - } - - for encrypted_transaction in data.transactions { - let e_t = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - TransactionPointer::::to_encrypted_data_from_record( - encrypted_transaction, - )? - } - _ => TransactionPointer::::to_encrypted_data_from_record( - encrypted_transaction, - )?, - }; - store_encrypted_data(e_t)?; - } - - for encrypted_deployment in data.deployments { - let e_t = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - DeploymentPointer::::to_encrypted_data_from_record(encrypted_deployment)? - } - _ => { - DeploymentPointer::::to_encrypted_data_from_record(encrypted_deployment)? - } - }; - store_encrypted_data(e_t)?; - } - - for encrypted_transition in data.transitions { - let e_t = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - TransitionPointer::::to_encrypted_data_from_record(encrypted_transition)? - } - _ => { - TransitionPointer::::to_encrypted_data_from_record(encrypted_transition)? - } - }; - store_encrypted_data(e_t)?; - } - - Ok("Data recovered and stored locally".to_string()) - - //now store the encoded/encrypted -} - -#[cfg(test)] -mod encrypted_data_tests { - use super::*; - use crate::api::encrypted_data::{delete_all_server_storage, post_encrypted_data}; - use std::str::FromStr; - - use crate::models::pointers::{ - record::AvailRecord, transaction::TransactionPointer, transition::TransitionPointer, - }; - use crate::models::storage::languages::Languages; - use crate::services::local_storage::persistent_storage::initial_user_preferences; - - use crate::services::local_storage::session::view::VIEWSESSION; - use crate::services::local_storage::storage_api::records::{ - encrypt_and_store_records, get_test_record_pointer, - }; - - use snarkvm::prelude::{PrivateKey, Testnet3, ToBytes, ViewKey}; - - use avail_common::models::constants::*; - - fn test_setup_prerequisites() { - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let view_key = ViewKey::::try_from(&pk).unwrap(); - - delete_user_encrypted_data().unwrap(); - - delete_user_preferences().unwrap(); - // initialize the user preferences - initial_user_preferences( - false, - None, - None, - false, - false, - view_key.to_address().to_string(), - Languages::English, - ) - .unwrap(); - initialize_encrypted_data_table().unwrap(); - - VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); - } - - #[test] - fn test_store_encrypted_data() { - test_setup_prerequisites(); - - let test_pointer = get_test_record_pointer(); - let address = get_address::().unwrap(); - - let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); - - println!("{:?}", encrypted_record); - // println!("{:?}", res); - } - - #[test] - fn test_get_encrypted_data_by_flavour() { - //test_store_encrypted_data(); - - VIEWSESSION - .set_view_session("AViewKey1myvhAr2nes8MF1y8gPV19azp4evwsBR4CqyzAi62nufW") - .unwrap(); - - let res = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record).unwrap(); - - let v_key = VIEWSESSION.get_instance::().unwrap(); - - let records = res - .iter() - .map(|x| { - let encrypted_data = x.to_enrypted_struct::().unwrap(); - let block: AvailRecord = encrypted_data.decrypt(v_key).unwrap(); - - block - }) - .collect::>>(); - - for record in records { - println!("{:?}\n", record); - } - } - - #[test] - fn test_get_encrypted_data_by_flavour_no_decrypt() { - let res = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record).unwrap(); - - for data in res { - println!("{:?}\n", data); - } - } - - #[test] - fn test_get_encrypted_data_by_id() { - test_setup_prerequisites(); - - let test_pointer = get_test_record_pointer(); - let address = get_address::().unwrap(); - - let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); - - let res = get_encrypted_data_by_id(&encrypted_record[0].id.unwrap().to_string()).unwrap(); - - println!("{:?}", res); - } - - #[test] - fn test_update_encrypted_data_by_id() { - test_setup_prerequisites(); - - let test_pointer = get_test_record_pointer(); - - let address = get_address::().unwrap(); - - let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); - - let res = update_encrypted_data_by_id( - &encrypted_record[0].id.unwrap().to_string(), - "ciphertext", - "nonce", - ); - - assert!(res.is_ok()); - } - - #[test] - fn test_delete_encrypted_data_by_id() { - test_setup_prerequisites(); - - let test_pointer = get_test_record_pointer(); - let address = get_address::().unwrap(); - - let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); - - let res = delete_encrypted_data_by_id(&encrypted_record[0].id.unwrap().to_string()); - assert!(res.is_ok()); - } - - #[test] - fn test_delete_user() { - delete_user_encrypted_data().unwrap(); - } - - #[test] - fn test_drop_encrypted_data() { - let storage = PersistentStorage::new().unwrap(); - - let query = "DROP TABLE encrypted_data"; - - storage.execute_query(query).unwrap(); - } - - #[tokio::test] - async fn test_get_and_store_all_data() { - test_setup_prerequisites(); - - let test_pointer = get_test_record_pointer(); - let address = get_address::().unwrap(); - - let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); - - post_encrypted_data(encrypted_record.clone()).await.unwrap(); - - let res = get_and_store_all_data().await.unwrap(); - println!("{:?}", res); - - delete_all_server_storage().await.unwrap(); - } -} diff --git a/backend/src/services/local_storage/persistent_storage.rs b/backend/src/services/local_storage/persistent_storage.rs deleted file mode 100644 index 3ba96b58..00000000 --- a/backend/src/services/local_storage/persistent_storage.rs +++ /dev/null @@ -1,489 +0,0 @@ -use chrono::{DateTime, Utc}; -use snarkvm::prelude::*; - -use crate::models::{event::Network as EventNetwork, storage::languages::Languages}; -use crate::{ - api::aleo_client::{setup_client, setup_local_client}, - models::storage::persistent::PersistentStorage, -}; - -use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; - -///Definition: Initialises the user preferences table in persistent storage -pub fn initial_user_preferences( - auth_type: bool, - username: Option, - tag: Option, - import: bool, - backup: bool, - address: String, - language: Languages, -) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - let api_client = setup_client::().unwrap(); - - let latest_height = match import { - true => 0, - false => api_client.latest_height()?, - }; - - let last_tx_sync = Utc::now(); - - storage.execute_query( - "CREATE TABLE IF NOT EXISTS user_preferences ( - theme TEXT NOT NULL, - language TEXT NOT NULL, - network TEXT NOT NULL, - auth_type BOOLEAN NOT NULL DEFAULT FALSE, - username TEXT, - tag TEXT, - last_sync INTEGER NOT NULL, - last_tx_sync TIMESTAMP NOT NULL, - last_backup_sync TIMESTAMP, - backup BOOLEAN NOT NULL DEFAULT FALSE, - address TEXT NOT NULL - )", - )?; - - let username = match username { - Some(username) => username, - None => "".to_string(), - }; - - let tag = tag.unwrap_or(0); - - storage.save_mixed( - vec![ - &"dark", - &language.to_string_short(), - // TODO - V2 change default to mainnet - &"testnet3", - &auth_type, - &username, - &tag, - &latest_height, - &last_tx_sync, - &Some(Utc::now()), - &address, - &backup - ], - "INSERT INTO user_preferences (theme, language, network, auth_type, username, tag, last_sync, last_tx_sync, last_backup_sync, address, backup) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9,?10, ?11)".to_string(), - )?; - - Ok(()) -} - -///Deletes user preferences table from persistent storage -> This should be reset -#[tauri::command(rename_all = "snake_case")] -pub fn delete_user_preferences() -> AvailResult<()> { - let storage = PersistentStorage::new()?; - let query = "DROP TABLE user_preferences"; - - match storage.execute_query(query) { - Ok(r) => r, - Err(e) => match e.error_type { - AvailErrorType::NotFound => {} - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - e.internal_msg, - "Error deleting user preferences".to_string(), - )) - } - }, - }; - - Ok(()) -} - -///Switch authentication type between password and biometrics -pub fn change_auth_type() -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - let query = "SELECT auth_type FROM user_preferences".to_string(); - - let res = storage.get_all::(&query, 1)?; - - let auth_type = res[0][0]; - - let new_auth_type = !auth_type; - - storage.save( - vec![&new_auth_type], - "UPDATE user_preferences SET auth_type = ?1".to_string(), - )?; - - Ok(()) -} - -/// Get authentication type from user preferences -#[tauri::command(rename_all = "snake_case")] -pub fn get_auth_type() -> AvailResult { - let storage = PersistentStorage::new()?; - - let query = "SELECT auth_type FROM user_preferences".to_string(); - - let res = storage.get_all::(&query, 1)?; - - let auth_type = res[0][0].clone(); - - Ok(auth_type) -} - -///get username from user preferences -#[tauri::command(rename_all = "snake_case")] -pub fn get_username() -> AvailResult { - let storage = PersistentStorage::new()?; - - let query = "SELECT username || '#' || tag AS username_tag FROM user_preferences;".to_string(); - - let res = storage.get_all::(&query, 1)?; - - match res.get(0) { - Some(username) => { - if username[0] == "#0" { - return get_address_string(); - } else { - return Ok(username[0].clone()); - } - } - None => Err(AvailError::new( - AvailErrorType::LocalStorage, - "No username found".to_string(), - "No username found".to_string(), - )), - } -} - -pub fn update_username_local(username: &str, tag: i32) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - storage.save( - vec![Box::new(username.to_string()), Box::new(tag.to_string())], - "UPDATE user_preferences SET username = ?1, tag = ?2".to_string(), - )?; - - Ok(()) -} - -/// Get network from user preferences -#[tauri::command(rename_all = "snake_case")] -pub fn get_network() -> AvailResult { - let storage = PersistentStorage::new()?; - let query = "SELECT network FROM user_preferences".to_string(); - - let res = storage.get_all::(&query, 1)?; - - match res.get(0) { - Some(network) => Ok(network[0].clone()), - None => Err(AvailError::new( - AvailErrorType::LocalStorage, - "No network found".to_string(), - "No network found".to_string(), - )), - } -} - -/// Update network in user preferences -#[tauri::command(rename_all = "snake_case")] -pub fn update_network(network: EventNetwork) { - let storage = PersistentStorage::new().unwrap(); - - storage - .save( - vec![Box::new(network.to_string())], - "UPDATE user_preferences SET network = ?1".to_string(), - ) - .unwrap(); -} - -///get last sync height from user preferences -#[tauri::command(rename_all = "snake_case")] -pub fn get_last_sync() -> AvailResult { - let storage = PersistentStorage::new()?; - - let query = "SELECT last_sync FROM user_preferences".to_string(); - - let res = storage.get_all::(&query, 1)?; - - match res.get(0) { - Some(last_sync) => Ok(last_sync[0].to_owned()), - None => Err(AvailError::new( - AvailErrorType::LocalStorage, - "No last sync height found".to_string(), - "No last sync height found".to_string(), - )), - } -} - -///update last sync height in user preferences -pub fn update_last_sync(height: u32) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - storage.save( - vec![&height], - "UPDATE user_preferences SET last_sync = ?1".to_string(), - )?; - - Ok(()) -} - -fn handle_no_backup_found() -> AvailResult> { - let backup_flag = get_backup_flag()?; - - match backup_flag { - true => { - // TODO - store everything since the creation of time and then update backup height - - Err(AvailError::new( - AvailErrorType::LocalStorage, - "No last backup height found, your encrypted data is being backed up.".to_string(), - "No last backup height found, your encrypted data is being backed up".to_string(), - )) - } - false => Ok(Utc::now()), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_last_backup_sync() -> AvailResult> { - let storage = PersistentStorage::new()?; - - let query = "SELECT last_backup_sync FROM user_preferences".to_string(); - - let res = storage.get_all::>>(&query, 1)?; - - match res.get(0) { - Some(last_backup) => match last_backup[0] { - Some(last_backup) => Ok(last_backup.to_owned()), - None => handle_no_backup_found(), - }, - None => handle_no_backup_found(), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub fn update_last_backup_sync(timestamp: DateTime) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - storage.save( - vec![×tamp], - "UPDATE user_preferences SET last_backup_sync = ?1".to_string(), - )?; - - Ok(()) -} - -/// get last transactions sync time from user preferences -pub fn get_last_tx_sync() -> AvailResult { - let storage = PersistentStorage::new()?; - - let query = "SELECT last_tx_sync FROM user_preferences".to_string(); - - let res = storage.get_all::>(&query, 1)?; - - let last_tx_sync = res[0][0].clone().timestamp(); - - Ok(last_tx_sync) -} - -/// update last transactions sync time in user preferences -pub fn update_last_tx_sync(timestamp: DateTime) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - storage.save( - vec![×tamp], - "UPDATE user_preferences SET last_tx_sync = ?1".to_string(), - )?; - - Ok(()) -} - -/// get public address from view session -pub fn get_address() -> AvailResult> { - let storage = PersistentStorage::new()?; - let query = "SELECT address FROM user_preferences".to_string(); - - let res = storage.get_all::(&query, 1)?; - - match res.get(0) { - Some(address) => Ok(Address::::from_str(&address[0])?), - None => Err(AvailError::new( - AvailErrorType::LocalStorage, - "No address found".to_string(), - "No address found".to_string(), - )), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_address_string() -> AvailResult { - let storage = PersistentStorage::new()?; - let query = "SELECT address FROM user_preferences".to_string(); - - let res = storage.get_all::(&query, 1)?; - - match res.get(0) { - Some(address) => Ok(address[0].clone()), - None => Err(AvailError::new( - AvailErrorType::LocalStorage, - "No address found".to_string(), - "No address found".to_string(), - )), - } -} - -pub fn update_address(address: &str) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - storage.save( - vec![Box::new(address.to_string())], - "UPDATE user_preferences SET address = ?1".to_string(), - )?; - - Ok(()) -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_backup_flag() -> AvailResult { - let storage = PersistentStorage::new()?; - - let query = "SELECT backup FROM user_preferences".to_string(); - - let res = storage.get_all::(&query, 1)?; - - let backup = res[0].clone(); - - Ok(backup[0]) -} - -#[tauri::command(rename_all = "snake_case")] -pub fn update_local_backup_flag(backup: bool) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - storage.save( - vec![&backup], - "UPDATE user_preferences SET backup = ?1".to_string(), - )?; - - Ok(()) -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_language() -> AvailResult { - let storage = PersistentStorage::new()?; - - let query = "SELECT language FROM user_preferences".to_string(); - - let res = storage.get_all::(&query, 1)?; - - let language = match Languages::from_string_short(&res[0][0]) { - Some(language) => language, - None => Languages::English, - }; - - Ok(language) -} - -#[tauri::command(rename_all = "snake_case")] -pub fn update_language(language: Languages) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - storage.save( - vec![Box::new(language.to_string_short())], - "UPDATE user_preferences SET language = ?1".to_string(), - )?; - - Ok(()) -} - -#[test] -fn test_initial_user_preferences() { - initial_user_preferences( - true, - Some("Test".to_string()), - Some(1234), - false, - false, - "address".to_string(), - Languages::English, - ) - .unwrap(); - - let storage = PersistentStorage::new().unwrap(); - - let query = "SELECT auth_type FROM user_preferences".to_string(); - - let res = storage.get_all::(&query, 1).unwrap(); - - print!("{:?}", res[0][0]); - assert_eq!(res[0][0], "true".to_string()); -} - -#[test] -fn test_delete_user_preferences() { - delete_user_preferences().unwrap(); -} - -#[test] -fn test_change_auth_type() { - change_auth_type().unwrap(); - - let res = get_auth_type().unwrap(); - - assert_eq!(res, false); -} - -#[test] -fn test_get_last_sync() { - let res = get_last_sync().unwrap(); - - print!("{}", res); -} - -#[test] -fn test_update_last_sync() { - update_last_sync(88329u32).unwrap(); -} - -#[test] -fn test_get_username() { - let res = get_username().unwrap(); - - print!("{}", res); -} - -#[test] -fn test_get_network() { - let res = get_network().unwrap(); - - print!("{}", res); - assert_eq!(res, "testnet3".to_string()); -} - -#[test] -fn test_get_address() { - let address = get_address::().unwrap(); - - print!("{}", address); -} - -#[test] -fn test_get_address_string() { - let address = get_address_string().unwrap(); - - print!("{}", address); -} - -#[test] -fn test_get_backup_flag() { - let backup = get_backup_flag().unwrap(); - - print!("{}", backup); -} - -#[test] -fn test_update_backup_flag() { - update_local_backup_flag(true).unwrap(); -} diff --git a/backend/src/services/local_storage/session.rs b/backend/src/services/local_storage/session.rs deleted file mode 100644 index ef0ace9e..00000000 --- a/backend/src/services/local_storage/session.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod password; -pub mod view; diff --git a/backend/src/services/local_storage/session/password.rs b/backend/src/services/local_storage/session/password.rs deleted file mode 100644 index 2d84d188..00000000 --- a/backend/src/services/local_storage/session/password.rs +++ /dev/null @@ -1,75 +0,0 @@ -use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; -use once_cell::sync::Lazy; -use std::{ - sync::{Arc, RwLock}, - time::{Duration, Instant}, -}; - -pub struct PassSession { - password: RwLock>, - expiration: RwLock, -} - -impl PassSession { - pub fn new() -> Self { - Self { - password: RwLock::new(None), - expiration: RwLock::new(Instant::now()), - } - } - - pub fn set_pass_session(&self, password: &str) -> AvailResult<()> { - let mut password_lock = self.password.write().unwrap(); - let mut expiration_lock = self.expiration.write().unwrap(); - *password_lock = Some(password.to_string()); - - // Set expiration to 5 minutes from now - *expiration_lock = Instant::now() + Duration::from_secs(5 * 60); - Ok(()) - } - - pub fn extend_session(&self) -> AvailResult<()> { - let mut expiration_lock = self.expiration.write().unwrap(); - // Extend expiration to 5 minutes from now - *expiration_lock = Instant::now() + Duration::from_secs(5 * 60); - Ok(()) - } - - pub fn get_instance(&self) -> AvailResult { - let expiration_lock = self.expiration.read().unwrap(); - if Instant::now() > *expiration_lock { - let mut password_lock = self.password.write().unwrap(); - *password_lock = None; // Clear the password as session expired - - return Err(AvailError::new( - AvailErrorType::Unauthorized, - "Session expired, please reauthenticate.".to_string(), - "Session expired, please reauthenticate.".to_string(), - )); - } - drop(expiration_lock); // Release the read lock before acquiring the write lock - - let password_lock = self.password.read().unwrap(); - match &*password_lock { - Some(password) => Ok(password.to_owned()), - None => Err(AvailError::new( - AvailErrorType::Unauthorized, - "Unauthorized, please reauthenticate.".to_string(), - "Unauthorized, please reauthenticate.".to_string(), - )), - } - } -} - -pub static PASS: Lazy> = Lazy::new(|| Arc::new(PassSession::new())); - -mod test_pass_session { - use super::*; - - #[test] - fn test_pass_session() { - PASS.set_pass_session("password").unwrap(); - let password = PASS.get_instance().unwrap(); - assert_eq!(password, "password"); - } -} diff --git a/backend/src/services/local_storage/session/view.rs b/backend/src/services/local_storage/session/view.rs deleted file mode 100644 index b0ff8777..00000000 --- a/backend/src/services/local_storage/session/view.rs +++ /dev/null @@ -1,59 +0,0 @@ -use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; -use once_cell::sync::Lazy; -use std::{ - str::FromStr, - sync::{Arc, RwLock}, -}; - -use snarkvm::prelude::{Network, ViewKey}; - -pub struct ViewSession { - view_key: RwLock>, -} - -impl ViewSession { - pub fn new() -> Self { - Self { - view_key: RwLock::new(None), - } - } - - pub fn set_view_session(&self, view_key: &str) -> AvailResult<()> { - let mut view_key_lock = self.view_key.write().unwrap(); - *view_key_lock = Some(view_key.to_string()); - Ok(()) - } - - pub fn get_instance(&self) -> AvailResult> { - let view_key_lock = self.view_key.read().unwrap(); - let view_key = match &*view_key_lock { - Some(view_key) => view_key, - None => { - return Err(AvailError::new( - AvailErrorType::Validation, - "View Key not found".to_string(), - "View Key not found".to_string(), - )) - } - }; - let view_key = ViewKey::::from_str(view_key)?; - Ok(view_key) - } -} - -pub static VIEWSESSION: Lazy> = Lazy::new(|| Arc::new(ViewSession::new())); - -mod test_view_session { - - use super::*; - use avail_common::models::constants::*; - use snarkvm::prelude::Testnet3; - - #[test] - fn test_view_session() { - let view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY).unwrap(); - VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); - let view_key = VIEWSESSION.get_instance::().unwrap(); - assert_eq!(view_key.to_string(), TESTNET3_VIEW_KEY); - } -} diff --git a/backend/src/services/local_storage/storage_api.rs b/backend/src/services/local_storage/storage_api.rs deleted file mode 100644 index 402d5df1..00000000 --- a/backend/src/services/local_storage/storage_api.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod deployment; -pub mod event; -pub mod records; -pub mod transaction; -pub mod transition; -// pub mod tokens; diff --git a/backend/src/services/local_storage/storage_api/deployment.rs b/backend/src/services/local_storage/storage_api/deployment.rs deleted file mode 100644 index e26a821e..00000000 --- a/backend/src/services/local_storage/storage_api/deployment.rs +++ /dev/null @@ -1,147 +0,0 @@ -use chrono::{DateTime, Local}; -use snarkvm::prelude::{transactions::Transactions, Address, Network, Testnet3}; -use std::str::FromStr; - -use crate::models::{event::Event, pointers::deployment::DeploymentPointer}; -use crate::services::local_storage::encrypted_data::store_encrypted_data; -use crate::services::local_storage::{ - encrypted_data::{get_encrypted_data_by_flavour, get_encrypted_data_by_id}, - persistent_storage::get_network, - session::view::VIEWSESSION, -}; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::{ - encrypted_data::{EncryptedData, EncryptedDataTypeCommon, TransactionState}, - network::SupportedNetworks, - }, -}; - -/* -- Deployments -- */ -pub fn find_encrypt_store_deployments( - transactions: &Transactions, - height: u32, - timestamp: DateTime, - address: Address, - stored_transaction_ids: Vec, -) -> AvailResult> { - let deployment_pointers = transactions - .iter() - .map(|tx| { - if stored_transaction_ids.contains(&tx.id()) { - return None; - } - let deployment = tx.deployment(); - let owner = tx.owner(); - if let Some(deployment) = deployment { - let owner = owner.unwrap(); - match owner.address() == address { - true => { - let base_fee = match tx.base_fee_amount() { - Ok(fee) => fee, - Err(_) => return None, - }; - let priority_fee = match tx.priority_fee_amount() { - Ok(fee) => fee, - Err(_) => return None, - }; - let fee = *(base_fee + priority_fee) as f64 / 1000000.0; - - let deployment_pointer = DeploymentPointer::new( - Some(tx.id().to_owned()), - deployment.program_id().to_string(), - fee, - TransactionState::Confirmed, - Some(height), - None, - timestamp, - Some(timestamp), - None, - ); - - Some(deployment_pointer) - } - false => None, - } - } else { - None - } - }) - .filter_map(|x| x) - .collect::>(); - - let encrypted_deployments = deployment_pointers - .iter() - .map(|dp| { - let encrypted_dp = dp.to_encrypted_data(address)?; - store_encrypted_data(encrypted_dp.clone())?; - Ok(encrypted_dp) - }) - .collect::>>()?; - - Ok(encrypted_deployments) -} - -pub fn get_deployment_pointer(id: &str) -> AvailResult> { - let encrypted_deployment = get_encrypted_data_by_id(id)?; - - let deployment = decrypt_deployments::(vec![encrypted_deployment])?; - - Ok(deployment[0].to_owned()) -} - -// TODO - make generic to all encrypted data with Deserialize trait bound -pub fn decrypt_deployments( - encrypted_deployments: Vec, -) -> AvailResult>> { - let network = get_network()?; - - let v_key = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => VIEWSESSION.get_instance::()?, - _ => VIEWSESSION.get_instance::()?, - }; - - let deployments = encrypted_deployments - .iter() - .map(|x| { - let encrypted_data = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => x.to_enrypted_struct::()?, - _ => x.to_enrypted_struct::()?, - }; - - let deployment: DeploymentPointer = encrypted_data.decrypt(v_key)?; - - Ok(deployment) - }) - .collect::>>>()?; - - Ok(deployments) -} - -pub fn decrypt_deployment(encrypted_deployment: EncryptedData) -> AvailResult { - let v_key = VIEWSESSION.get_instance::()?; - - let db_id = match encrypted_deployment.id { - Some(id) => id.to_string(), - None => Err(AvailError::new( - AvailErrorType::Internal, - "No id found".to_string(), - "No Id Found".to_string(), - ))?, - }; - - let encrypted_data = encrypted_deployment.to_enrypted_struct::()?; - - let deployment: DeploymentPointer = encrypted_data.decrypt(v_key)?; - - deployment.to_event(&db_id) -} - -pub fn get_deployment_pointers() -> AvailResult>> { - let encrypted_deployments = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Deployment)?; - - decrypt_deployments(encrypted_deployments) -} - -mod deployment_storage_api_test {} diff --git a/backend/src/services/local_storage/storage_api/event.rs b/backend/src/services/local_storage/storage_api/event.rs deleted file mode 100644 index fc3674eb..00000000 --- a/backend/src/services/local_storage/storage_api/event.rs +++ /dev/null @@ -1,539 +0,0 @@ -use std::cmp::max; - -use rusqlite::params; -use snarkvm::prelude::Network; - -use crate::models::pointers::{ - deployment::DeploymentPointer, transaction::TransactionPointer, transition::TransitionPointer, -}; -use crate::models::wallet_connect::get_event::GetEventsRequest; -use crate::models::{ - event::{AvailEvent, Event, SuccinctAvailEvent}, - storage::persistent::PersistentStorage, -}; -use crate::services::local_storage::{ - encrypted_data::{get_encrypted_data_by_id, handle_encrypted_data_query}, - persistent_storage::{get_address_string, get_network}, -}; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::encrypted_data::{EncryptedData, EncryptedDataTypeCommon}, -}; - -/// Gets an Event by its encrypted data id -pub fn get_event_raw(id: &str) -> AvailResult { - let encrypted_event = get_encrypted_data_by_id(id)?; - let event = match encrypted_event.flavour { - EncryptedDataTypeCommon::Transition => { - TransitionPointer::::decrypt_to_event(encrypted_event)? - } - EncryptedDataTypeCommon::Transaction => { - TransactionPointer::::decrypt_to_event(encrypted_event)? - } - EncryptedDataTypeCommon::Deployment => { - DeploymentPointer::::decrypt_to_event(encrypted_event)? - } - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Unknown encrypted data flavour".to_string(), - "Unknown Transaction Type".to_string(), - )) - } - }; - - Ok(event) -} - -/// Gets an Avail Event by its encrypted data id -pub fn get_avail_event_raw(id: &str) -> AvailResult { - let encrypted_event = get_encrypted_data_by_id(id)?; - let event = match encrypted_event.flavour { - EncryptedDataTypeCommon::Transition => { - TransitionPointer::::decrypt_to_avail_event(encrypted_event)? - } - EncryptedDataTypeCommon::Transaction => { - TransactionPointer::::decrypt_to_avail_event(encrypted_event)? - } - EncryptedDataTypeCommon::Deployment => { - DeploymentPointer::::decrypt_to_avail_event(encrypted_event)? - } - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Unknown encrypted data flavour".to_string(), - "Unknown Transaction Type".to_string(), - )) - } - }; - - Ok(event) -} - -/// Gets a Succinct Avail Event by its encrypted data id -pub fn get_succinct_avail_event_raw(id: &str) -> AvailResult { - let encrypted_event = get_encrypted_data_by_id(id)?; - let event = match encrypted_event.flavour { - EncryptedDataTypeCommon::Transition => { - TransitionPointer::::decrypt_to_succinct_avail_event(encrypted_event)? - } - EncryptedDataTypeCommon::Transaction => { - TransactionPointer::::decrypt_to_succinct_avail_event(encrypted_event)? - } - EncryptedDataTypeCommon::Deployment => { - DeploymentPointer::::decrypt_to_succinct_avail_event(encrypted_event)? - } - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Unknown encrypted data flavour".to_string(), - "Unknown Transaction Type".to_string(), - )) - } - }; - - Ok(event) -} - -pub fn get_events_raw(request: GetEventsRequest) -> AvailResult> { - let address = get_address_string()?; - let network = get_network()?; - - // Query for transitions and deployments - let transitions_deployments_query = format!( - "SELECT *, '[]' as json_program_ids, '[]' as json_function_ids FROM encrypted_data WHERE flavour IN ('{}','{}') AND owner='{}' AND network='{}'", - EncryptedDataTypeCommon::Transition.to_str(), - EncryptedDataTypeCommon::Deployment.to_str(), - address, - network - ); - - // Query for transactions - let transactions_query = format!( - "SELECT *, program_ids as json_program_ids, function_ids as json_function_ids FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", - EncryptedDataTypeCommon::Transaction.to_str(), - address, - network - ); - - // Applying filters - let mut common_filter_conditions = String::new(); - if let Some(filter) = request.filter { - if let Some(event_type) = filter.event_type { - common_filter_conditions - .push_str(&format!(" AND event_type='{}'", event_type.to_str())); - } - - if let Some(program_id) = filter.program_id { - // Adjust this to handle both cases (string equality for transitions/deployments and JSON array contains for transactions) - common_filter_conditions.push_str(&format!( - " AND (program_ids='{}' OR JSON_EXTRACT(json_program_ids, '$') LIKE '%{}%')", - program_id, program_id - )); - } - - if let Some(function_id) = filter.function_id { - // Similar adjustment for function_ids - common_filter_conditions.push_str(&format!( - " AND (function_ids='{}' OR JSON_EXTRACT(json_function_ids, '$') LIKE '%{}%')", - function_id, function_id - )); - } - } - - let transitions_deployments_query_with_filters = format!( - "{} {}", - transitions_deployments_query, common_filter_conditions - ); - - let transactions_query_with_filters = - format!("{} {}", transactions_query, common_filter_conditions); - - let mut combined_query = format!( - "{} UNION ALL {} ORDER BY created_at DESC", - transitions_deployments_query_with_filters, transactions_query_with_filters - ); - - let mut encrypted_data: Vec = vec![]; - - if let Some(page) = request.page { - let fetch_limit = (page * 6) + 6; - - combined_query = format!( - "{} UNION ALL {} ORDER BY created_at DESC LIMIT {}", - transitions_deployments_query_with_filters, - transactions_query_with_filters, - fetch_limit - ); - - let page_start = (page * 6) as usize; - let page_end = page_start + 6; - - let encrypted_data_result = handle_encrypted_data_query(&combined_query)?; - let page_encrypted_data = encrypted_data_result[page_start.min(encrypted_data_result.len()) - ..page_end.min(encrypted_data_result.len())] - .to_vec(); - encrypted_data = page_encrypted_data; - } else { - encrypted_data = handle_encrypted_data_query(&combined_query)?; - } - - let mut events: Vec = vec![]; - for encrypted_transaction in encrypted_data { - let event = match encrypted_transaction.flavour { - EncryptedDataTypeCommon::Transition => { - TransitionPointer::::decrypt_to_event(encrypted_transaction)? - } - EncryptedDataTypeCommon::Transaction => { - TransactionPointer::::decrypt_to_event(encrypted_transaction)? - } - EncryptedDataTypeCommon::Deployment => { - DeploymentPointer::::decrypt_to_event(encrypted_transaction)? - } - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Unknown encrypted data flavour".to_string(), - "Unknown Transaction Type".to_string(), - )) - } - }; - - events.push(event); - } - - Ok(events) -} - -// Get Avail Events with filter -pub fn get_avail_events_raw(request: GetEventsRequest) -> AvailResult> { - let address = get_address_string()?; - let network = get_network()?; - - // Query for transitions and deployments - let transitions_deployments_query = format!( - "SELECT *, '[]' as json_program_ids, '[]' as json_function_ids FROM encrypted_data WHERE flavour IN ('{}','{}') AND owner='{}' AND network='{}'", - EncryptedDataTypeCommon::Transition.to_str(), - EncryptedDataTypeCommon::Deployment.to_str(), - address, - network - ); - - // Query for transactions - let transactions_query = format!( - "SELECT *, program_ids as json_program_ids, function_ids as json_function_ids FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", - EncryptedDataTypeCommon::Transaction.to_str(), - address, - network - ); - - // Applying filters - let mut common_filter_conditions = String::new(); - if let Some(filter) = request.filter { - if let Some(event_type) = filter.event_type { - common_filter_conditions - .push_str(&format!(" AND event_type='{}'", event_type.to_str())); - } - - if let Some(program_id) = filter.program_id { - // Adjust this to handle both cases (string equality for transitions/deployments and JSON array contains for transactions) - common_filter_conditions.push_str(&format!( - " AND (program_ids='{}' OR JSON_EXTRACT(json_program_ids, '$') LIKE '%{}%')", - program_id, program_id - )); - } - - if let Some(function_id) = filter.function_id { - // Similar adjustment for function_ids - common_filter_conditions.push_str(&format!( - " AND (function_ids='{}' OR JSON_EXTRACT(json_function_ids, '$') LIKE '%{}%')", - function_id, function_id - )); - } - } - - let transitions_deployments_query_with_filters = format!( - "{} {}", - transitions_deployments_query, common_filter_conditions - ); - - let transactions_query_with_filters = - format!("{} {}", transactions_query, common_filter_conditions); - - let mut combined_query = format!( - "{} UNION ALL {} ORDER BY created_at DESC", - transitions_deployments_query_with_filters, transactions_query_with_filters - ); - - let mut encrypted_data: Vec = vec![]; - - if let Some(page) = request.page { - let fetch_limit = (page * 6) + 6; - - combined_query = format!( - "{} UNION ALL {} ORDER BY created_at DESC LIMIT {}", - transitions_deployments_query_with_filters, - transactions_query_with_filters, - fetch_limit - ); - - let page_start = (page * 6) as usize; - let page_end = page_start + 6; - - let encrypted_data_result = handle_encrypted_data_query(&combined_query)?; - let page_encrypted_data = encrypted_data_result[page_start.min(encrypted_data_result.len()) - ..page_end.min(encrypted_data_result.len())] - .to_vec(); - encrypted_data = page_encrypted_data; - } else { - encrypted_data = handle_encrypted_data_query(&combined_query)?; - } - - let mut events: Vec = vec![]; - - for encrypted_transaction in encrypted_data { - let event = match encrypted_transaction.flavour { - EncryptedDataTypeCommon::Transition => { - TransitionPointer::::decrypt_to_avail_event(encrypted_transaction)? - } - EncryptedDataTypeCommon::Transaction => { - TransactionPointer::::decrypt_to_avail_event(encrypted_transaction)? - } - EncryptedDataTypeCommon::Deployment => { - DeploymentPointer::::decrypt_to_avail_event(encrypted_transaction)? - } - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Unknown encrypted data flavour".to_string(), - "Unknown Transaction Type".to_string(), - )) - } - }; - - events.push(event); - } - - Ok(events) -} - -pub fn get_succinct_avail_events_raw( - request: GetEventsRequest, -) -> AvailResult> { - let address = get_address_string()?; - let network = get_network()?; - - // Query for transitions and deployments - let transitions_deployments_query = format!( - "SELECT *, '[]' as json_program_ids, '[]' as json_function_ids FROM encrypted_data WHERE flavour IN ('{}','{}') AND owner='{}' AND network='{}'", - EncryptedDataTypeCommon::Transition.to_str(), - EncryptedDataTypeCommon::Deployment.to_str(), - address, - network - ); - - // Query for transactions - let transactions_query = format!( - "SELECT *, program_ids as json_program_ids, function_ids as json_function_ids FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", - EncryptedDataTypeCommon::Transaction.to_str(), - address, - network - ); - - // Applying filters - let mut common_filter_conditions = String::new(); - if let Some(filter) = request.filter { - if let Some(event_type) = filter.event_type { - common_filter_conditions - .push_str(&format!(" AND event_type='{}'", event_type.to_str())); - } - - if let Some(program_id) = filter.program_id { - // Adjust this to handle both cases (string equality for transitions/deployments and JSON array contains for transactions) - common_filter_conditions.push_str(&format!( - " AND (program_ids='{}' OR JSON_EXTRACT(json_program_ids, '$') LIKE '%{}%')", - program_id, program_id - )); - } - - if let Some(function_id) = filter.function_id { - // Similar adjustment for function_ids - common_filter_conditions.push_str(&format!( - " AND (function_ids='{}' OR JSON_EXTRACT(json_function_ids, '$') LIKE '%{}%')", - function_id, function_id - )); - } - } - - let transitions_deployments_query_with_filters = format!( - "{} {}", - transitions_deployments_query, common_filter_conditions - ); - - let transactions_query_with_filters = - format!("{} {}", transactions_query, common_filter_conditions); - - let mut combined_query = format!( - "{} UNION ALL {} ORDER BY created_at DESC", - transitions_deployments_query_with_filters, transactions_query_with_filters - ); - - let mut encrypted_data: Vec = vec![]; - - if let Some(page) = request.page { - let fetch_limit = (page * 6) + 6; - - combined_query = format!( - "{} UNION ALL {} ORDER BY created_at DESC LIMIT {}", - transitions_deployments_query_with_filters, - transactions_query_with_filters, - fetch_limit - ); - - let page_start = (page * 6) as usize; - let page_end = page_start + 6; - - let encrypted_data_result = handle_encrypted_data_query(&combined_query)?; - let page_encrypted_data = encrypted_data_result[page_start.min(encrypted_data_result.len()) - ..page_end.min(encrypted_data_result.len())] - .to_vec(); - encrypted_data = page_encrypted_data; - } else { - encrypted_data = handle_encrypted_data_query(&combined_query)?; - } - - let mut events: Vec = vec![]; - - for encrypted_transaction in encrypted_data { - let event = match encrypted_transaction.flavour { - EncryptedDataTypeCommon::Transition => { - TransitionPointer::::decrypt_to_succinct_avail_event(encrypted_transaction)? - } - EncryptedDataTypeCommon::Transaction => { - TransactionPointer::::decrypt_to_succinct_avail_event(encrypted_transaction)? - } - EncryptedDataTypeCommon::Deployment => { - DeploymentPointer::::decrypt_to_succinct_avail_event(encrypted_transaction)? - } - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Unknown encrypted data flavour".to_string(), - "Unknown Transaction Type".to_string(), - )) - } - }; - - events.push(event); - } - - Ok(events) -} - -/* --Utilities-- */ - -/// Calculates how many pages of events are available -pub fn transaction_pages_available() -> AvailResult { - let storage = PersistentStorage::new()?; - - let address = get_address_string()?; - let network = get_network()?; - - let events_per_page = 6; - let count_query = " - SELECT COUNT(*) FROM encrypted_data - WHERE flavour IN (?,?,?) - AND owner = ? - AND network = ?"; - - let total_count: i64 = storage.conn.query_row( - count_query, - params![ - EncryptedDataTypeCommon::Transition.to_str(), - EncryptedDataTypeCommon::Transaction.to_str(), - EncryptedDataTypeCommon::Deployment.to_str(), - address, - network - ], - |row| row.get(0), - )?; - // Calculate the number of pages - let total_pages = max( - 1, - (total_count as f64 / events_per_page as f64).ceil() as i64, - ); - Ok(total_pages) -} - -#[cfg(test)] -mod events_tests { - use std::str::FromStr; - - use super::*; - use snarkvm::prelude::{PrivateKey, Testnet3, ToBytes, ViewKey}; - - use crate::{ - models::wallet_connect::get_event::EventsFilter, - services::local_storage::{persistent_storage::update_address, session::view::VIEWSESSION}, - }; - use avail_common::models::constants::TESTNET_PRIVATE_KEY; - - #[test] - fn test_get_event_raw() { - let event = get_event_raw::( - String::from("5aa9d8f2-7d74-40fc-ae64-457dc188d598").as_str(), - ) - .unwrap(); - println!("{:?}", event); - } - - #[test] - fn test_get_avail_event_raw() { - let event = get_avail_event_raw::( - String::from("5aa9d8f2-7d74-40fc-ae64-457dc188d598").as_str(), - ) - .unwrap(); - println!("{:?}", event); - } - - #[test] - fn test_get_events_raw() { - let event_filter = EventsFilter { - event_type: None, - program_id: None, - function_id: Some("transfer_public_to_private".to_string()), - }; - let request = GetEventsRequest { - filter: Some(event_filter), - page: Some(0), - }; - - let event = get_events_raw::(request).unwrap(); - println!("{:?}", event); - } - - #[test] - fn test_get_avail_events_raw() { - VIEWSESSION - .set_view_session("AViewKey1dRUJgozQcBf2rntQqoGYfViNy4A3Khx9RZVwuX3kSNCx") - .unwrap(); - let event = get_avail_events_raw::(GetEventsRequest::default()).unwrap(); - println!("{:?}", event); - } - - #[test] - fn test_get_succinct_avail_events_raw() { - VIEWSESSION - .set_view_session("AViewKey1dRUJgozQcBf2rntQqoGYfViNy4A3Khx9RZVwuX3kSNCx") - .unwrap(); - let event = get_succinct_avail_events_raw::(GetEventsRequest::default()).unwrap(); - println!("{:?}", event); - } - - #[test] - fn test_transaction_pages_available() { - let event_pages = transaction_pages_available().unwrap(); - println!("{:?}", event_pages); - } -} diff --git a/backend/src/services/local_storage/storage_api/records.rs b/backend/src/services/local_storage/storage_api/records.rs deleted file mode 100644 index 380cb396..00000000 --- a/backend/src/services/local_storage/storage_api/records.rs +++ /dev/null @@ -1,641 +0,0 @@ -use std::str::FromStr; - -use avail_common::errors::AvailError; -use snarkvm::circuit::integers::Integer; -use snarkvm::circuit::{Identifier, Inject}; -use snarkvm::prelude::{ - bail, Address, AleoID, Entry, Field, Literal, Network, Plaintext, Testnet3, ToField, -}; - -use crate::api::encrypted_data::update_data; -use crate::models::pointers::record::{AvailRecord, Metadata, Pointer}; -use crate::models::storage::persistent::PersistentStorage; -use crate::models::wallet_connect::records::{GetRecordsRequest, RecordFilterType}; -use crate::services::local_storage::encrypted_data::{ - get_encrypted_data_by_id, get_encrypted_data_by_nonce, handle_encrypted_data_query, - update_encrypted_data_spent_by_id, -}; -use crate::services::local_storage::persistent_storage::get_address_string; -use crate::services::local_storage::tokens::{add_balance, subtract_balance}; -use crate::services::local_storage::{ - encrypted_data::{get_encrypted_data_by_flavour, store_encrypted_data}, - persistent_storage::{get_address, get_network}, - session::view::VIEWSESSION, -}; - -use avail_common::{ - errors::AvailResult, - models::{ - constants::{TRANSITION_PREFIX, TX_PREFIX}, - encrypted_data::{EncryptedData, EncryptedDataTypeCommon, RecordTypeCommon}, - traits::encryptable::Encryptable, - }, -}; - -/// Encrypts record pointers using the wallet owner's address and stores them in persistent storage -pub fn encrypt_and_store_records( - record_pointers: Vec>, - address: Address, -) -> AvailResult> { - let encrypted_records = record_pointers - .iter() - .map(|record| { - let encrypted_record = record.to_encrypted_data(address)?; - - store_encrypted_data(encrypted_record.clone())?; - - Ok(encrypted_record) - }) - .collect::>>()?; - - Ok(encrypted_records) -} - -fn decrypt_record_pointers( - encrypted_data: Vec, -) -> AvailResult>> { - let view_key = VIEWSESSION.get_instance::()?; - - let records = encrypted_data - .iter() - .map(|x| { - let encrypted_data = x.to_enrypted_struct::()?; - - let record: AvailRecord = encrypted_data.decrypt(view_key)?; - - Ok(record) - }) - .collect::>>>()?; - - Ok(records) -} - -pub fn get_record_pointers( - request: GetRecordsRequest, -) -> AvailResult<(Vec>, Vec)> { - // TODO - use address to filter when supporting hd wallets - let address = match request.address() { - Some(address) => address.clone(), - None => get_address_string()?, - }; - - let mut base_query = format!( - "SELECT * FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", - EncryptedDataTypeCommon::Record.to_str(), - address, - get_network()?, - ); - - if let Some(filter) = request.filter() { - match RecordFilterType::from_string(filter.record_type()) { - RecordFilterType::Spent => base_query.push_str(" AND spent=true"), - RecordFilterType::Unspent => base_query.push_str(" AND spent=false"), - _ => (), - } - - let program_ids = filter.program_ids(); - if !program_ids.is_empty() { - let program_ids_list = program_ids - .iter() - .map(|id| format!("'{}'", id)) - .collect::>() - .join(", "); - base_query.push_str(&format!(" AND program_ids IN ({})", program_ids_list)); - } - - match filter.function_id() { - Some(function_id) => { - base_query.push_str(&format!(" AND function_ids='{}'", function_id)); - } - None => (), - } - - match filter.record_name() { - Some(record_name) => { - base_query.push_str(&format!(" AND record_name='{}'", record_name)); - } - None => (), - } - } - - if let Some(page) = request.page() { - base_query.push_str(&format!(" LIMIT 50 OFFSET {}", page * 50)); - } - - let encrypted_records = handle_encrypted_data_query(&base_query)?; - - let encrypted_record_pointers_ids = encrypted_records - .iter() - .map(|x| x.id.clone().unwrap().to_string()) - .collect::>(); - - let record_pointers = decrypt_record_pointers::(encrypted_records)?; - - Ok((record_pointers, encrypted_record_pointers_ids)) -} - -pub fn get_page_count_for_filter(request: GetRecordsRequest) -> AvailResult { - let address = match request.address() { - Some(address) => address.clone(), - None => get_address_string()?, - }; - - let db = PersistentStorage::new()?; - - let mut base_query = format!( - "SELECT COUNT(*) FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}'", - EncryptedDataTypeCommon::Record.to_str(), - address, - get_network()?, - ); - - if let Some(filter) = request.filter() { - match RecordFilterType::from_string(filter.record_type()) { - RecordFilterType::Spent => base_query.push_str(" AND spent=true"), - RecordFilterType::Unspent => base_query.push_str(" AND spent=false"), - _ => (), - } - - let program_ids = filter.program_ids(); - if !program_ids.is_empty() { - let program_ids_list = program_ids - .iter() - .map(|id| format!("'{}'", id)) - .collect::>() - .join(", "); - base_query.push_str(&format!(" AND program_ids IN ({})", program_ids_list)); - } - - match filter.function_id() { - Some(function_id) => { - base_query.push_str(&format!(" AND function_ids='{}'", function_id)); - } - None => (), - } - - match filter.record_name() { - Some(record_name) => { - base_query.push_str(&format!(" AND record_name='{}'", record_name)); - } - None => (), - } - } - let mut query_statement = db.conn.prepare(base_query.as_str())?; - let count: i32 = query_statement.query_row([], |row| row.get(0))?; - - let page_count = count / 50; - - Ok(page_count) -} - -pub fn get_record_pointers_ids() -> AvailResult<(Vec>, Vec)> { - let encrypted_records = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record)?; - - let encrypted_record_pointers_ids = encrypted_records - .iter() - .map(|x| x.id.clone().unwrap().to_string()) - .collect::>(); - - let record_pointers = decrypt_record_pointers::(encrypted_records)?; - - Ok((record_pointers, encrypted_record_pointers_ids)) -} - -pub fn get_record_pointers_for_record_type( - record_type: RecordTypeCommon, - address: &str, -) -> AvailResult<(Vec>, Vec)> { - let network = get_network()?; - - let query = format!( - "SELECT * FROM encrypted_data WHERE flavour='{}' AND owner='{}' AND network='{}' AND record_type='{}';", - EncryptedDataTypeCommon::Record.to_str(), - address, - network, - record_type.to_str() - ); - - let encrypted_record_pointers = handle_encrypted_data_query(&query)?; - - let encrypted_record_pointers_ids = encrypted_record_pointers - .iter() - .map(|x| x.id.unwrap().to_string()) - .collect::>(); - - let record_pointers = decrypt_record_pointers::(encrypted_record_pointers)?; - - Ok((record_pointers, encrypted_record_pointers_ids)) -} - -/* Utilities */ - -/// Update record spent status on local storage via nonce -pub fn update_record_spent_local_via_nonce( - nonce: &str, - spent: bool, -) -> AvailResult<()> { - let address = get_address::()?; - - let v_key = VIEWSESSION.get_instance::()?; - - if let Some(encrypted_data) = get_encrypted_data_by_nonce(nonce)? { - let encrypted_data_id = match encrypted_data.id { - Some(id) => id.to_string(), - None => { - return Err(AvailError::new( - avail_common::errors::AvailErrorType::Internal, - "No id found for encrypted data".to_string(), - "No id found for encrypted data".to_string(), - )) - } - }; - - println!( - "Updating record spent {} status for id: {}", - spent, encrypted_data_id - ); - - let encrypted_struct = encrypted_data.to_enrypted_struct::()?; - - let mut record_pointer: AvailRecord = encrypted_struct.decrypt(v_key)?; - - if record_pointer.metadata.spent == spent { - return Ok(()); - } - - record_pointer.metadata.spent = spent; - if record_pointer.clone().metadata.record_type == RecordTypeCommon::Tokens - || record_pointer.clone().metadata.record_type == RecordTypeCommon::AleoCredits - { - let record = record_pointer.clone().to_record()?; - let record_data_keys = record.data().clone().into_keys(); - let record_name = record_pointer.clone().metadata.name; - for key in record_data_keys { - let is_key: bool = matches!(key.to_string().as_str(), "amount" | "microcredits"); - - if is_key { - let balance_entry = match record.data().get(&key.clone()) { - Some(bal) => Ok(bal), - None => Err(()), - }; - - let balance = match balance_entry.unwrap() { - Entry::Private(Plaintext::Literal(Literal::::U64(amount), _)) => { - **amount - } - Entry::Public(Plaintext::Literal(Literal::::U64(amount), _)) => **amount, - Entry::Constant(Plaintext::Literal(Literal::::U64(amount), _)) => { - **amount - } - _ => 0u64, - }; - - //let balance_field = balance_f.to_be_bytes(); - //let balance = u64::from_be_bytes(balance_field); - - let _ = match spent { - true => subtract_balance(&record_name, &balance.to_string(), v_key)?, - false => add_balance(&record_name, &balance.to_string(), v_key)?, - }; - } - } - } - let updated_record_pointer = record_pointer.encrypt_for(address)?; - - update_encrypted_data_spent_by_id( - &encrypted_data_id, - &updated_record_pointer.cipher_text.to_string(), - &updated_record_pointer.nonce.to_string(), - spent, - )?; - } - - Ok(()) -} - -pub fn check_if_record_exists(nonce: &str) -> AvailResult { - let encrypted_data = get_encrypted_data_by_nonce(nonce)?; - - if let Some(encrypted_data) = encrypted_data { - Ok(encrypted_data.id.is_some()) - } else { - Ok(false) - } -} - -/// Update record spent status on local storage -pub fn update_record_spent_local(id: &str, spent: bool) -> AvailResult<()> { - let address = get_address::()?; - - let v_key = VIEWSESSION.get_instance::()?; - - let encrypted_data = get_encrypted_data_by_id(id)?; - - let encrypted_struct = encrypted_data.to_enrypted_struct::()?; - - let mut record_pointer: AvailRecord = encrypted_struct.decrypt(v_key)?; - - if record_pointer.metadata.spent == spent { - return Ok(()); - } - - record_pointer.metadata.spent = spent; - if record_pointer.clone().metadata.record_type == RecordTypeCommon::Tokens - || record_pointer.clone().metadata.record_type == RecordTypeCommon::AleoCredits - { - let record = record_pointer.clone().to_record()?; - let record_data_keys = record.data().clone().into_keys(); - let record_name = record_pointer.clone().metadata.name; - for key in record_data_keys { - let is_key: bool = matches!(key.to_string().as_str(), "amount" | "microcredits"); - - if is_key { - let balance_entry = match record.data().get(&key.clone()) { - Some(bal) => Ok(bal), - None => Err(()), - }; - - let balance = match balance_entry.unwrap() { - Entry::Private(Plaintext::Literal(Literal::::U64(amount), _)) => **amount, - Entry::Public(Plaintext::Literal(Literal::::U64(amount), _)) => **amount, - Entry::Constant(Plaintext::Literal(Literal::::U64(amount), _)) => **amount, - _ => 0u64, - }; - - //let balance_field = balance_f.to_be_bytes(); - //let balance = u64::from_be_bytes(balance_field); - - let _ = match spent { - true => subtract_balance(&record_name, &balance.to_string(), v_key)?, - false => add_balance(&record_name, &balance.to_string(), v_key)?, - }; - } - } - } - let updated_record_pointer = record_pointer.encrypt_for(address)?; - - update_encrypted_data_spent_by_id( - id, - &updated_record_pointer.cipher_text.to_string(), - &updated_record_pointer.nonce.to_string(), - spent, - )?; - Ok(()) -} - -/// Update record spent on encrypted backup after local storage has been updated -pub async fn update_records_spent_backup(ids: Vec) -> AvailResult<()> { - let encrypted_data = ids - .iter() - .map(|id| { - let data = get_encrypted_data_by_id(id)?; - Ok(data) - }) - .collect::>>()?; - - update_data(encrypted_data, ids).await?; - // update status server side via id - Ok(()) -} - -///For Testing purposes -pub fn get_test_record_pointer() -> AvailRecord { - let test_transaction_id = AleoID::, TX_PREFIX>::from_str( - "at1zux4zw83dayxtndd58skuy7qq7xg0d6ez86ak9zlqh2zru4kgggqjys70g", - ) - .unwrap(); - let test_transition_id = AleoID::, TRANSITION_PREFIX>::from_str( - "au1070w2eknk90ldz2rs88p8erdjq5we4787hr702pf3lmzxsr4kg8sr5lran", - ) - .unwrap(); - - let test_record_pointer: AvailRecord = AvailRecord { - pointer: Pointer { - block_height: 10u32, - transaction_id: test_transaction_id, - transition_id: test_transition_id, - commitment: "test_commitment".to_string(), - tag: "test_tag".to_string(), - index: 0u8, - owner: "address".to_string(), - }, - metadata: Metadata { - record_type: RecordTypeCommon::AleoCredits, - program_id: "credits.aleo".to_string(), - function_id: "transfer_public_to_private".to_string(), - spent: false, - name: "credits.record".to_string(), - nonce: "test_nonce".to_string(), - }, - }; - - test_record_pointer -} - -#[cfg(test)] -mod records_storage_api_tests { - use super::*; - use crate::api::encrypted_data::{delete_all_server_storage, post_encrypted_data}; - use crate::models::storage::languages::Languages; - use crate::models::wallet_connect::records::{wc_Record, RecordWithPlaintext, RecordsFilter}; - - use crate::services::local_storage::encrypted_data::{ - delete_user_encrypted_data, drop_encrypted_data_table, - }; - - use crate::services::local_storage::{ - encrypted_data::initialize_encrypted_data_table, - persistent_storage::{delete_user_preferences, initial_user_preferences, update_address}, - session::view::VIEWSESSION, - }; - use avail_common::models::constants::*; - use snarkvm::prelude::{PrivateKey, ToBytes, ViewKey}; - - fn test_setup_prerequisites() { - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let view_key = ViewKey::::try_from(&pk).unwrap(); - - delete_user_encrypted_data().unwrap(); - delete_user_preferences().unwrap(); - // initialize the user preferences - initial_user_preferences( - false, - None, - None, - false, - false, - view_key.to_address().to_string(), - Languages::English, - ) - .unwrap(); - initialize_encrypted_data_table().unwrap(); - - VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); - } - - #[test] - fn test_store_view_session() { - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let view_key = ViewKey::::try_from(&pk).unwrap(); - - VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); - } - - #[test] - fn test_encrypt_and_store_records() { - test_setup_prerequisites(); - - let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); - let test_record_pointer = get_test_record_pointer(); - - let encrypted_records = - encrypt_and_store_records::(vec![test_record_pointer], address).unwrap(); - - print!("{:?}", encrypted_records); - assert_eq!(encrypted_records.len(), 1); - } - - #[test] - fn test_get_record_pointers() { - // test_store_view_session(); - - VIEWSESSION - .set_view_session("AViewKey1pViDeDV8dT1yTCdzU6ojxh8GdFDadSasRpk6mZdyz8mh") - .unwrap(); - - //let test_record_pointer = get_test_record_pointer(); - - let record_filter = RecordsFilter::new( - vec!["credits.aleo".to_string()], - None, - RecordFilterType::All, - Some("credits.record".to_string()), - ); - - let request = GetRecordsRequest::new(None, Some(record_filter), None); - let (pointers, _ids) = get_record_pointers::(request).unwrap(); - - print!("Pointers {:?}", pointers); - - // assert!(pointers == vec![test_record_pointer]); - } - - #[test] - fn test_get_record_pointers_for_record_type() { - test_store_view_session(); - let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); - let test_record_pointer = get_test_record_pointer(); - - let pointers = get_record_pointers_for_record_type::( - RecordTypeCommon::AleoCredits, - &address.to_string(), - ) - .unwrap(); - - print!("Pointers \n {:?}", pointers); - - assert!(pointers.0 == vec![test_record_pointer]); - } - - #[test] - fn test_get_record_pointer_for_program_id() { - test_store_view_session(); - let test_record_pointer = get_test_record_pointer(); - let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); - - let record_filter = RecordsFilter::new( - vec!["credits.aleo".to_string()], - None, - RecordFilterType::All, - None, - ); - - let request = GetRecordsRequest::new(Some(address.to_string()), Some(record_filter), None); - - let (pointers, _ids) = get_record_pointers::(request).unwrap(); - - print!("Pointers \n {:?}", pointers); - - assert!(pointers == vec![test_record_pointer]); - } - - #[test] - fn test_get_record_pointer_for_program_id_and_function_id() { - test_store_view_session(); - let test_record_pointer = get_test_record_pointer(); - let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); - - let record_filter = RecordsFilter::new( - vec!["credits.aleo".to_string()], - Some("transfer_public_to_private".to_string()), - RecordFilterType::All, - None, - ); - - let request = GetRecordsRequest::new(Some(address.to_string()), Some(record_filter), None); - - let (pointers, _ids) = get_record_pointers::(request).unwrap(); - - print!("Pointers \n {:?}", pointers); - - assert!(pointers == vec![test_record_pointer]); - } - - #[test] - fn test_get_record_pointer_for_program_id_and_record_name() { - test_store_view_session(); - let test_record_pointer = get_test_record_pointer(); - let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); - let record_filter = RecordsFilter::new( - vec!["credits.aleo".to_string()], - None, - RecordFilterType::All, - Some("credits.record".to_string()), - ); - - let request = GetRecordsRequest::new(Some(address.to_string()), Some(record_filter), None); - let (pointers, _ids) = get_record_pointers::(request).unwrap(); - - print!("Pointers \n {:?}", pointers); - drop_encrypted_data_table().unwrap(); - assert!(pointers == vec![test_record_pointer]); - } - - #[test] - fn test_x() { - let test_record_pointer = get_test_record_pointer(); - RecordWithPlaintext::from_record_pointer(test_record_pointer, "id".to_string()).unwrap(); - } - - #[tokio::test] - async fn test_update_record_status() { - test_setup_prerequisites(); - - let test_pointer = get_test_record_pointer(); - let address = get_address::().unwrap(); - - let encrypted_record = encrypt_and_store_records(vec![test_pointer], address).unwrap(); - - post_encrypted_data(encrypted_record.clone()).await.unwrap(); - - let res = update_records_spent_backup::(vec![encrypted_record[0] - .id - .unwrap() - .to_string()]) - .await - .unwrap(); - println!("{:?}", res); - - delete_all_server_storage().await.unwrap(); - } - - #[test] - fn test_check_if_record_exists() { - VIEWSESSION - .set_view_session("AViewKey1myvhAr2nes8MF1y8gPV19azp4evwsBR4CqyzAi62nufW") - .unwrap(); - - let res = check_if_record_exists::("").unwrap(); - println!("{:?}", res); - } -} diff --git a/backend/src/services/local_storage/storage_api/transaction.rs b/backend/src/services/local_storage/storage_api/transaction.rs deleted file mode 100644 index 3bfa303e..00000000 --- a/backend/src/services/local_storage/storage_api/transaction.rs +++ /dev/null @@ -1,471 +0,0 @@ -use chrono::{DateTime, Local, Utc}; -use snarkvm::prelude::Network; - -use crate::models::{ - event::Event, - pointers::{ - deployment::DeploymentPointer, transaction::TransactionPointer, - transition::TransitionPointer, - }, -}; -use crate::services::local_storage::encrypted_data::{ - get_encrypted_data_by_id, handle_encrypted_data_query, handle_encrypted_data_query_params, - update_encrypted_transaction_state_by_id, -}; -use crate::services::local_storage::{ - encrypted_data::get_encrypted_data_by_flavour, - persistent_storage::{get_address, get_network}, - session::view::VIEWSESSION, -}; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::encrypted_data::{EncryptedData, EncryptedDataTypeCommon, TransactionState}, -}; - -use super::{deployment::get_deployment_pointer, records::update_record_spent_local_via_nonce}; - -pub fn get_transactions_exec() -> AvailResult>> { - let encrypted_transactions = - get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transaction)?; - - let transactions = decrypt_transactions_exec(encrypted_transactions)?; - - Ok(transactions) -} - -pub fn get_transaction_pointer(id: &str) -> AvailResult> { - let encrypted_transaction = get_encrypted_data_by_id(id)?; - - let transaction = decrypt_transactions_exec::(vec![encrypted_transaction])?; - - Ok(transaction[0].to_owned()) -} - -pub fn decrypt_transactions_exec( - encrypted_transactions: Vec, -) -> AvailResult>> { - let v_key = VIEWSESSION.get_instance::()?; - - let transactions = encrypted_transactions - .iter() - .map(|x| { - let encrypted_data = x.to_enrypted_struct::()?; - - let tx_in: TransactionPointer = encrypted_data.decrypt(v_key)?; - - Ok(tx_in) - }) - .collect::>>>()?; - - Ok(transactions) -} - -pub fn decrypt_transaction_exec(encrypted_tx: EncryptedData) -> AvailResult { - let v_key = VIEWSESSION.get_instance::()?; - - let encrypted_data = encrypted_tx.to_enrypted_struct::()?; - - let tx_out: TransactionPointer = encrypted_data.decrypt(v_key)?; - - let event_id = match encrypted_tx.id { - Some(id) => id.to_string(), - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "No event id found".to_string(), - "No event id found".to_string(), - )) - } - }; - - tx_out.to_event(&event_id) -} - -/* Utilities */ -// get all transactions from a certain synced_on date forward and return Vector of transaction id string -pub fn get_tx_ids_from_date( - date: DateTime, -) -> AvailResult> { - let address = get_address::()?; - let network = get_network()?; - - // get a timestamp from 2 hours ago - let timestamp = date.with_timezone(&Utc); - let timestamp_2_hours_ago = timestamp - chrono::Duration::hours(2); - - let query = format!( - "SELECT * FROM encrypted_data WHERE flavour IN ('{}','{}','{}') AND owner='{}' AND network='{}' AND created_at >= ?1", - EncryptedDataTypeCommon::Transition.to_str(), - EncryptedDataTypeCommon::Transaction.to_str(), - EncryptedDataTypeCommon::Deployment.to_str(), - address, - network - ); - - let encrypted_transactions = - handle_encrypted_data_query_params(&query, vec![timestamp_2_hours_ago])?; - - let mut transaction_ids: Vec = Vec::new(); - - for encrypted_transaction in encrypted_transactions { - let encrypted_struct = encrypted_transaction.to_enrypted_struct::()?; - match encrypted_transaction.flavour { - EncryptedDataTypeCommon::Transition => { - let transition: TransitionPointer = - encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; - transaction_ids.push(transition.transaction_id); - } - EncryptedDataTypeCommon::Transaction => { - let tx_exec: TransactionPointer = - encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; - if let Some(id) = tx_exec.transaction_id() { - transaction_ids.push(id); - } - } - EncryptedDataTypeCommon::Deployment => { - let deployment: DeploymentPointer = - encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; - if let Some(id) = deployment.id { - transaction_ids.push(id); - } - } - _ => {} - }; - } - - Ok(transaction_ids) -} - -pub fn get_transaction_ids() -> AvailResult> { - let address = get_address::()?; - let network = get_network()?; - - let query = format!( - "SELECT * FROM encrypted_data WHERE flavour IN ('{}','{}','{}') AND owner='{}' AND network='{}'", - EncryptedDataTypeCommon::Transition.to_str(), - EncryptedDataTypeCommon::Transaction.to_str(), - EncryptedDataTypeCommon::Deployment.to_str(), - address, - network - ); - - let encrypted_transactions = handle_encrypted_data_query(&query)?; - - let mut transaction_ids: Vec = Vec::new(); - - for encrypted_transaction in encrypted_transactions { - let encrypted_struct = encrypted_transaction.to_enrypted_struct::()?; - match encrypted_transaction.flavour { - EncryptedDataTypeCommon::Transition => { - let transition: TransitionPointer = - encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; - transaction_ids.push(transition.transaction_id); - } - EncryptedDataTypeCommon::Transaction => { - let tx_exec: TransactionPointer = - encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; - - if let Some(id) = tx_exec.transaction_id() { - transaction_ids.push(id); - } - } - EncryptedDataTypeCommon::Deployment => { - let deployment: DeploymentPointer = - encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; - if let Some(id) = deployment.id { - transaction_ids.push(id); - } - } - _ => {} - }; - } - - Ok(transaction_ids) -} - -pub fn get_unconfirmed_and_failed_transaction_ids( -) -> AvailResult> { - let address = get_address::()?; - let network = get_network()?; - - let query = format!( - "SELECT * FROM encrypted_data WHERE flavour IN ('{}','{}','{}') AND state IN ('{}','{}') AND owner='{}' AND network='{}'", - EncryptedDataTypeCommon::Transition.to_str(), - EncryptedDataTypeCommon::Transaction.to_str(), - EncryptedDataTypeCommon::Deployment.to_str(), - TransactionState::Pending.to_str(), - TransactionState::Failed.to_str(), - address, - network - ); - - let encrypted_transactions = handle_encrypted_data_query(&query)?; - - let mut transaction_ids: Vec<(N::TransactionID, String)> = Vec::new(); - - for encrypted_transaction in encrypted_transactions { - let encrypted_struct = encrypted_transaction.to_enrypted_struct::()?; - match encrypted_transaction.flavour { - EncryptedDataTypeCommon::Transition => { - let transition: TransitionPointer = - encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; - if let Some(id) = encrypted_transaction.id { - transaction_ids.push((transition.transaction_id, id.to_string())); - } - } - EncryptedDataTypeCommon::Transaction => { - let tx_exec: TransactionPointer = - encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; - - if let Some(tx_id) = tx_exec.transaction_id() { - if let Some(id) = encrypted_transaction.id { - transaction_ids.push((tx_id, id.to_string())); - } - } - } - EncryptedDataTypeCommon::Deployment => { - let deployment: DeploymentPointer = - encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; - if let Some(tx_id) = deployment.id { - if let Some(id) = encrypted_transaction.id { - transaction_ids.push((tx_id, id.to_string())); - } - } - } - _ => {} - }; - } - - Ok(transaction_ids) -} - -// gets unconfirmed transactions that have been unconfirmed for more than 10 minutes -fn get_expired_unconfirmed_transactions() -> AvailResult> { - let address = get_address::()?; - let network = get_network()?; - - let query = format!( - "SELECT * FROM encrypted_data WHERE flavour IN ('{}','{}','{}') AND state='{}' AND owner='{}' AND network='{}'", - EncryptedDataTypeCommon::Transition.to_str(), - EncryptedDataTypeCommon::Transaction.to_str(), - EncryptedDataTypeCommon::Deployment.to_str(), - TransactionState::Pending.to_str(), - address, - network - ); - - let now = Local::now(); - let encrypted_data = handle_encrypted_data_query(&query)?; - let mut encrypted_transactions_to_decrypt: Vec = vec![]; - - for encrypted_data in encrypted_data { - if now - .signed_duration_since(encrypted_data.created_at) - .num_minutes() - > 10 - { - println!("{:?}", encrypted_data.transaction_state.clone()); - encrypted_transactions_to_decrypt.push(encrypted_data); - } - } - Ok(encrypted_transactions_to_decrypt) -} - -// This function should get unconfirmed encryped and check if they have been unconfirmed for more than 10 minutes -// If they have this should update to failed and the records related to the transaction should be updated to unspent -pub fn check_unconfirmed_transactions() -> AvailResult<()> { - let expired_transactions = get_expired_unconfirmed_transactions::()?; - - for expired_transaction in expired_transactions { - let encrypted_struct = expired_transaction.to_enrypted_struct::()?; - match expired_transaction.flavour { - EncryptedDataTypeCommon::Transaction => { - let tx_exec: TransactionPointer = - encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; - - if let Some(id) = expired_transaction.id { - handle_transaction_failed::(&id.to_string())?; - } - - let spent_record_nonces = tx_exec.spent_record_pointers_nonces(); - for nonce in spent_record_nonces { - update_record_spent_local_via_nonce::(&nonce, false)?; - } - } - EncryptedDataTypeCommon::Deployment => { - let deployment: DeploymentPointer = - encrypted_struct.decrypt(VIEWSESSION.get_instance::()?)?; - - if let Some(id) = expired_transaction.id { - handle_deployment_failed::(&id.to_string())?; - } - - if let Some(fee_nonce) = deployment.spent_fee_nonce { - update_record_spent_local_via_nonce::(fee_nonce.as_str(), false)?; - } - } - _ => {} - }; - } - - Ok(()) -} - -pub fn handle_transaction_failed(pointer_id: &str) -> AvailResult<()> { - let address = get_address::()?; - let mut transaction_pointer = get_transaction_pointer::(pointer_id)?; - - transaction_pointer.update_failed_transaction( - "Transaction remained unconfirmed and failed, no records were spent.".to_string(), - ); - - let encrypted_failed_transaction = transaction_pointer.to_encrypted_data(address)?; - - update_encrypted_transaction_state_by_id( - pointer_id, - &encrypted_failed_transaction.ciphertext, - &encrypted_failed_transaction.nonce, - TransactionState::Failed, - )?; - - Ok(()) -} - -pub fn handle_deployment_failed(pointer_id: &str) -> AvailResult<()> { - let address = get_address::()?; - let mut deployment_pointer = get_deployment_pointer::(pointer_id)?; - - deployment_pointer.update_failed_deployment( - "Deployment remained unconfirmed and failed, no records were spent.".to_string(), - ); - - let encrypted_failed_deployment = deployment_pointer.to_encrypted_data(address)?; - - update_encrypted_transaction_state_by_id( - pointer_id, - &encrypted_failed_deployment.ciphertext, - &encrypted_failed_deployment.nonce, - TransactionState::Failed, - )?; - - Ok(()) -} - -#[cfg(test)] -mod tx_out_storage_api_tests { - use super::*; - use avail_common::models::{ - constants::*, - encrypted_data::{EventTypeCommon, TransactionState}, - }; - use chrono::Local; - use snarkvm::prelude::{Address, AleoID, Field, PrivateKey, Testnet3, ToBytes, ViewKey}; - use std::str::FromStr; - use uuid::Uuid; - - use crate::services::local_storage::{ - encrypted_data::{ - delete_user_encrypted_data, initialize_encrypted_data_table, store_encrypted_data, - }, - session::view::VIEWSESSION, - }; - - #[test] - fn test_store_view_session() { - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let view_key = ViewKey::::try_from(&pk).unwrap(); - - VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); - } - - #[test] - fn test_store_tx_out() { - delete_user_encrypted_data().unwrap(); - initialize_encrypted_data_table().unwrap(); - - let test_transaction_id = AleoID::, TX_PREFIX>::from_str( - "at1zux4zw83dayxtndd58skuy7qq7xg0d6ez86ak9zlqh2zru4kgggqjys70g", - ) - .unwrap(); - - let test_transaction_out = TransactionPointer::new( - Some("Test_User".to_string()), - Some(test_transaction_id), - TransactionState::Confirmed, - Some(100u32), - Some("test_program_id".to_string()), - Some("test_function_id".to_string()), - vec![], - vec![], - Local::now(), - Some(Local::now() + chrono::Duration::seconds(40)), - None, - EventTypeCommon::Send, - None, - None, - None, - ); - - let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); - let id = Uuid::new_v4(); - - let encrypted_tx_in = test_transaction_out.to_encrypted_data(address).unwrap(); - - store_encrypted_data(encrypted_tx_in).unwrap(); - } - - #[test] - fn test_get_transactions_out() { - test_store_tx_out(); - test_store_view_session(); - - let test_transaction_id = AleoID::, TX_PREFIX>::from_str( - "at1zux4zw83dayxtndd58skuy7qq7xg0d6ez86ak9zlqh2zru4kgggqjys70g", - ) - .unwrap(); - - let test_transaction_out = TransactionPointer::new( - Some("Test_User".to_string()), - Some(test_transaction_id), - TransactionState::Confirmed, - Some(100u32), - Some("test_program_id".to_string()), - Some("test_function_id".to_string()), - vec![], - vec![], - Local::now(), - Some(Local::now() + chrono::Duration::seconds(40)), - None, - EventTypeCommon::Send, - None, - None, - None, - ); - - let transactions_out = get_transactions_exec::().unwrap(); - - assert_eq!(vec![test_transaction_out], transactions_out) - } - - #[test] - fn test_get_unconfirmed_and_failed_transaction_ids() { - VIEWSESSION.set_view_session("AViewKey1jXL3nQ7ax6ft9qshgtTn8nXrkKNFjSBdbnjueFW5f2Gj"); - - let transactions_out = get_unconfirmed_and_failed_transaction_ids::().unwrap(); - - println!("{:?}", transactions_out); - } - - #[test] - fn test_get_transaction_ids_from_date() { - VIEWSESSION.set_view_session("AViewKey1jXL3nQ7ax6ft9qshgtTn8nXrkKNFjSBdbnjueFW5f2Gj"); - - let date = Local::now(); - let a_day_ago = date - chrono::Duration::days(1); - - let transactions_out = get_tx_ids_from_date::(a_day_ago).unwrap(); - - println!("{:?}", transactions_out); - } -} diff --git a/backend/src/services/local_storage/storage_api/transition.rs b/backend/src/services/local_storage/storage_api/transition.rs deleted file mode 100644 index 8a8c6ff5..00000000 --- a/backend/src/services/local_storage/storage_api/transition.rs +++ /dev/null @@ -1,123 +0,0 @@ -use snarkvm::prelude::{Address, Network}; - -use crate::models::pointers::transition::TransitionPointer; -use crate::services::local_storage::{ - encrypted_data::{get_encrypted_data_by_flavour, store_encrypted_data}, - session::view::VIEWSESSION, -}; - -use avail_common::{ - errors::AvailResult, - models::encrypted_data::{EncryptedData, EncryptedDataTypeCommon}, -}; - -/* -- Transitions -- */ - -pub fn get_transitions() -> AvailResult>> { - let encrypted_transitions = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transition)?; - - decrypt_transitions(encrypted_transitions) -} - -//TODO - Test how long this takes with multiple transactions to decrypt -pub fn get_transition_ids() -> AvailResult> { - let transitions = get_transitions::()?; - - // TODO - Get transitions from transition_pointers, TransactionPointer and TransactionMessage - let tx_ids = transitions - .iter() - .map(|transition| transition.id.to_string()) - .collect::>(); - - Ok(tx_ids) -} - -pub fn decrypt_transitions( - encrypted_transitions: Vec, -) -> AvailResult>> { - let v_key = VIEWSESSION.get_instance::()?; - - let transitions = encrypted_transitions - .iter() - .map(|x| { - let encrypted_data = x.to_enrypted_struct::()?; - - let tx_in: TransitionPointer = encrypted_data.decrypt(v_key)?; - - Ok(tx_in) - }) - .collect::>>>()?; - - Ok(transitions) -} - -fn encrypt_and_store_transitions( - transitions: Vec>, - address: Address, -) -> AvailResult> { - let encrypted_transitions = transitions - .iter() - .map(|transition| { - let encrypted_data = transition.to_encrypted_data(address)?; - - store_encrypted_data(encrypted_data.clone())?; - - Ok(encrypted_data) - }) - .collect::>>()?; - - Ok(encrypted_transitions) -} - -#[cfg(test)] -mod transitions_storage_api_tests { - use super::*; - use snarkvm::{ - prelude::{Field, Group, Identifier, Input, Output, ProgramID, Testnet3, Transition}, - utilities::{TestRng, Uniform}, - }; - use std::str::FromStr; - - #[test] - fn test_get_transitions() { - let transitions = get_transitions::().unwrap(); - - print!("Transitions \n {:?}", transitions) - } - #[test] - fn test_get_transitions_ids() { - let transition_ids = get_transition_ids::().unwrap(); - - print!("Transition IDs \n {:?}", transition_ids) - } - - fn initialise_test_transition() -> Transition { - let mut rng = TestRng::default(); - - let field = Field::::new(Uniform::rand(&mut rng)); - let program_identifier = Identifier::::from_str("test_program_id").unwrap(); - let domain_identifier = Identifier::::from_str("aleo").unwrap(); - - let program_id = - ProgramID::::try_from((program_identifier, domain_identifier)).unwrap(); - - let function_name = Identifier::::from_str("test").unwrap(); - - let input = Input::::Constant(field, None); - let output = Output::::Constant(field, None); - - let tpk = Group::::new(Uniform::rand(&mut rng)); - let tcm = Field::::new(Uniform::rand(&mut rng)); - let transition = Transition::::new( - program_id, - function_name, - vec![input], - vec![output], - tpk, - tcm, - ) - .unwrap(); - - transition - } -} diff --git a/backend/src/services/local_storage/tokens.rs b/backend/src/services/local_storage/tokens.rs deleted file mode 100644 index abbeaec0..00000000 --- a/backend/src/services/local_storage/tokens.rs +++ /dev/null @@ -1,328 +0,0 @@ -use crate::models::storage::persistent::PersistentStorage; -use avail_common::errors::{AvailError, AvailErrorType, AvailResult}; -use snarkvm::prelude::*; - -pub fn init_tokens_table() -> AvailResult<()> { - let storage = PersistentStorage::new()?; - storage.execute_query( - "CREATE TABLE IF NOT EXISTS ARC20_tokens ( - token_name TEXT PRIMARY KEY, - program_id TEXT NOT NULL, - balance_ciphertext TEXT NOT NULL, - nonce TEXT NOT NULL - )", - )?; - Ok(()) -} - -pub fn drop_tokens_table() -> AvailResult<()> { - let storage = PersistentStorage::new()?; - match storage.execute_query("DROP TABLE IF EXISTS ARC20_tokens") { - Ok(r) => r, - Err(e) => match e.error_type { - AvailErrorType::NotFound => {} - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - e.internal_msg, - "Error deleting tokens table".to_string(), - )) - } - }, - }; - - Ok(()) -} - -pub fn init_token( - token_name: &str, - program_id: &str, - encryption_address: &str, - balance: &str, -) -> AvailResult<()> { - let storage = PersistentStorage::new()?; - - storage.execute_query( - "CREATE TABLE IF NOT EXISTS ARC20_tokens ( - token_name TEXT PRIMARY KEY, - program_id TEXT NOT NULL, - balance_ciphertext TEXT NOT NULL, - nonce TEXT NOT NULL - )", - )?; - - let rng = &mut rand::thread_rng(); - let scalar = Scalar::::rand(rng); - let nonce = N::g_scalar_multiply(&scalar); - - let plaintext = Plaintext::::from_str(balance)?; - let address = Address::::from_str(encryption_address)?; - let encrypted_balance = plaintext.encrypt(&address, scalar)?; - - storage.save( - vec![ - token_name.to_string(), - program_id.to_string(), - encrypted_balance.to_string(), - nonce.to_string(), - ], - "INSERT INTO ARC20_tokens (token_name, program_id, balance_ciphertext, nonce) VALUES (?1, ?2, ?3, ?4)" - .to_string(), - )?; - - Ok(()) -} - -pub fn add_balance( - token_name: &str, - balance: &str, - vk: ViewKey, -) -> AvailResult { - let storage = PersistentStorage::new()?; - let query = format!( - "SELECT balance_ciphertext, nonce FROM ARC20_tokens WHERE token_name='{}' ", - token_name - ); - let res = storage.get_all::(&query, 2)?; - match res.get(0) { - Some(old_encrypted_balance) => { - let nonce = Group::::from_str(res[0].get(1).unwrap())?; - let ciphertext = Ciphertext::::from_str(&old_encrypted_balance[0])?; - let old_balance_string = ciphertext.decrypt(vk, nonce)?.to_string(); - let old_balance = old_balance_string.trim_end_matches("u64").parse::()?; - - let temp_balance = balance.trim_end_matches("u64").parse::()?; - let new_balance = match old_balance.checked_add(temp_balance) { - Some(bal) => Ok(bal), - None => Err(AvailError::new( - AvailErrorType::InvalidData, - "err".to_string(), - "edd".to_string(), - )), - }?; - let rng = &mut rand::thread_rng(); - let scalar = Scalar::::rand(rng); - let nonce = N::g_scalar_multiply(&scalar); - let new_encrypted_balance = Plaintext::::encrypt( - &Plaintext::::from_str(&format!("{}u64", new_balance))?, - &vk.to_address(), - scalar, - )?; - storage.save( - vec![new_encrypted_balance.to_string(), nonce.to_string()], - format!("UPDATE ARC20_tokens SET balance_ciphertext = ?1, nonce = ?2 WHERE token_name='{}'", token_name), - )?; - Ok(new_balance.to_string()) - } - None => Err(AvailError::new( - AvailErrorType::LocalStorage, - "None_found".to_string(), - "Nonefound".to_string(), - )), - } -} - -pub fn subtract_balance( - token_name: &str, - balance: &str, - vk: ViewKey, -) -> AvailResult { - let storage = PersistentStorage::new()?; - let query = format!( - "SELECT balance_ciphertext, nonce FROM ARC20_tokens WHERE token_name='{}' ", - token_name - ); - let res = storage.get_all::(&query, 2)?; - match res.get(0) { - Some(old_encrypted_balance) => { - let nonce = res[0].get(1).unwrap(); - let old_balance_string = Ciphertext::::decrypt( - &Ciphertext::::from_str(&old_encrypted_balance[0])?, - vk, - Group::::from_str(nonce)?, - )? - .to_string(); - let old_balance = old_balance_string.trim_end_matches("u64").parse::()?; - - let temp_balance = balance.trim_end_matches("u64").parse::()?; - let new_balance = match old_balance.checked_sub(temp_balance) { - Some(bal) => Ok(bal), - None => Err(AvailError::new( - AvailErrorType::InvalidData, - "err".to_string(), - "edd".to_string(), - )), - }?; - let rng = &mut rand::thread_rng(); - let scalar = Scalar::::rand(rng); - let nonce = N::g_scalar_multiply(&scalar); - let new_encrypted_balance = Plaintext::::encrypt( - &Plaintext::::from_str(&format!("{}u64", new_balance))?, - &vk.to_address(), - scalar, - )?; - storage.save( - vec![new_encrypted_balance.to_string(), nonce.to_string()], - format!("UPDATE ARC20_tokens SET balance_ciphertext = ?1, nonce = ?2 WHERE token_name='{}'", token_name), - )?; - Ok(new_balance.to_string()) - } - None => Err(AvailError::new( - AvailErrorType::LocalStorage, - "None_found".to_string(), - "Nonefound".to_string(), - )), - } -} - -pub fn get_balance(token_name: &str, vk: ViewKey) -> AvailResult { - let storage = PersistentStorage::new()?; - let query = format!( - "SELECT balance_ciphertext, nonce FROM ARC20_tokens WHERE token_name='{}' ", - token_name - ); - let res = storage.get_all::(&query, 2)?; - match res.get(0) { - Some(old_encrypted_balance) => { - let nonce = res[0].get(1).unwrap(); - let old_balance_string = Ciphertext::::decrypt( - &Ciphertext::::from_str(&old_encrypted_balance[0])?, - vk, - Group::::from_str(nonce)?, - )? - .to_string(); - Ok(old_balance_string) - } - None => Ok("0u64".to_string()), - } -} // wrap this func and with only token id as param and vk is - -pub fn if_token_exists(token_name: &str) -> AvailResult { - let storage = PersistentStorage::new()?; - let query = format!( - "SELECT balance_ciphertext FROM ARC20_tokens WHERE token_name='{}'", - token_name - ); - // let res = ?; - match storage.get_all::(&query, 1) { - Ok(balance) => { - println!("====> {:?}", balance); - if balance.is_empty() { - Ok(false) - } else { - Ok(true) - } - } - Err(_) => Ok(false), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_program_id_for_token(token_name: &str) -> AvailResult { - let storage = PersistentStorage::new()?; - let query = format!( - "SELECT program_id FROM ARC20_tokens WHERE token_name='{}'", - token_name - ); - // let res = ?; - let res = storage.get_all::(&query, 1)?; - match res.get(0) { - Some(p_id) => Ok(p_id[0].clone()), - None => Ok("".to_string()), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_stored_tokens() -> AvailResult> { - let storage = PersistentStorage::new()?; - let query = "SELECT token_name FROM ARC20_tokens"; - let res = storage.get_all::(query, 1)?; - - println!("Token ids ====> {:?}", res); - - Ok(res.iter().map(|x| x[0].clone()).collect()) -} - -pub fn delete_tokens_table() -> AvailResult<()> { - let storage = PersistentStorage::new()?; - let query = "DROP TABLE ARC20_tokens"; - - match storage.execute_query(query) { - Ok(r) => r, - Err(e) => match e.error_type { - AvailErrorType::NotFound => {} - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - e.internal_msg, - "Error deleting tokens table".to_string(), - )) - } - }, - }; - - Ok(()) -} - -mod test_tokens { - use super::*; - - use crate::api::aleo_client::{setup_client, setup_local_client}; - use crate::models::event::Network as EventNetwork; - use avail_common::{aleo_tools::api::AleoAPIClient, models::constants::*}; - - #[test] - fn test_init() { - let api_client: AleoAPIClient = setup_client::().unwrap(); - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let vk = ViewKey::::try_from(pk).unwrap(); - let res = - init_token::("testnew111.record", "diff.aleo", TESTNET_ADDRESS, "100u64") - .unwrap(); - } - #[test] - fn test_pid() { - let api_client: AleoAPIClient = setup_client::().unwrap(); - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let vk = ViewKey::::try_from(pk).unwrap(); - let res = get_program_id_for_token("testnew111.record").unwrap(); - println!("{:?}", res); - } - #[test] - fn test_add_balance() { - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let vk = ViewKey::::try_from(pk).unwrap(); - let res = add_balance("test_token", "100u64", vk).unwrap(); - println!("{:?}", res); - } - - #[test] - fn test_subtract_balance() { - let api_client: AleoAPIClient = setup_client::().unwrap(); - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let vk = ViewKey::::try_from(pk).unwrap(); - let res = subtract_balance("token1", "100u64", vk).unwrap(); - println!("{:?}", res); - } - - #[test] - fn test_get_balance() { - let api_client: AleoAPIClient = setup_client::().unwrap(); - let pk = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); - //let vk = ViewKey::::try_from(pk).unwrap(); - - let vk = - ViewKey::::from_str("AViewKey1rWpxoch574dTmVu9zRovZ5UKyhZeBv9ftP2MkEy6TJRF") - .unwrap(); - - let res = get_balance("credits.record", vk).unwrap(); - println!("{:?}", res); - } - - #[test] - fn test_record_exists() { - let api_client: AleoAPIClient = setup_client::().unwrap(); - let res = if_token_exists("token_not_existing").unwrap(); - println!("{:?}", res); - } -} diff --git a/backend/src/services/local_storage/utils.rs b/backend/src/services/local_storage/utils.rs deleted file mode 100644 index dfb4f867..00000000 --- a/backend/src/services/local_storage/utils.rs +++ /dev/null @@ -1,345 +0,0 @@ -use std::str::FromStr; - -use crate::api::encrypted_data::delete_all_server_storage; -use crate::api::user::delete_user; -use crate::models::storage::encryption::{Keys, Keys::PrivateKey as PKey, Keys::ViewKey as VKey}; -use crate::models::storage::languages::Languages; -use crate::models::wallet::BetterAvailWallet; -use crate::services::local_storage::{ - encrypted_data::drop_encrypted_data_table, - persistent_storage::{delete_user_preferences, get_backup_flag, get_language, get_network}, - session::view::VIEWSESSION, - tokens::drop_tokens_table, -}; -use avail_common::models::constants::VIEW_KEY; -use snarkvm::prelude::{ - Ciphertext, Field, Identifier, Network, PrivateKey, Signature, Testnet3, ViewKey, -}; - -use crate::services::account::key_management::key_controller::{ - linuxKeyController, macKeyController, windowsKeyController, KeyController, -}; - -use avail_common::{ - aleo_tools::encryptor::Encryptor, - converters::messages::{field_to_fields, utf8_string_to_bits}, - errors::{AvailError, AvailErrorType, AvailResult}, - models::{constants::PRIVATE_KEY, network::SupportedNetworks}, -}; - -#[tauri::command(rename_all = "snake_case")] -pub fn get_private_key_tauri(password: Option) -> AvailResult { - let network = get_network()?; - - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - let key = get_private_key::(password)?; - Ok(key.to_string()) - } - _ => Err(AvailError::new( - AvailErrorType::Internal, - "Invalid network.".to_string(), - "Invalid network.".to_string(), - )), - } -} - -pub fn get_private_key(password: Option) -> AvailResult> { - let key_manager = { - #[cfg(target_os = "macos")] - { - macKeyController - } - #[cfg(target_os = "windows")] - { - windowsKeyController - } - #[cfg(target_os = "linux")] - { - linuxKeyController - } - }; - - let key = match password { - Some(password) => key_manager.read_key(Some(&password), PRIVATE_KEY), - None => key_manager.read_key(None, PRIVATE_KEY), - }?; - - let private_key = match key { - Keys::PrivateKey(p) => p, - Keys::ViewKey(_) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Invalid key type.".to_string(), - "Invalid key type.".to_string(), - )) - } - }; - - Ok(private_key) -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_seed_phrase(password: Option) -> AvailResult { - let network = get_network()?; - - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - let key_manager = { - #[cfg(target_os = "macos")] - { - macKeyController - } - #[cfg(target_os = "windows")] - { - windowsKeyController - } - #[cfg(target_os = "linux")] - { - linuxKeyController - } - }; - - let val: Identifier = Identifier::::from_str("test")?; - - let seed_phrase = match password { - Some(password) => key_manager.read_phrase(&password, val), - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Password is required.".to_string(), - "Password is required.".to_string(), - )) - } - }?; - - Ok(seed_phrase) - } - } -} - -/// Get viewing key from keychain, also used as local authentication -#[tauri::command(rename_all = "snake_case")] -pub fn get_view_key_tauri(password: Option) -> AvailResult { - let network = get_network()?; - - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - let key = get_view_key::(password)?; - VIEWSESSION.set_view_session(&key.to_string())?; - - Ok(key.to_string()) - } - } -} - -pub fn get_view_key(password: Option) -> AvailResult> { - let key_manager = { - #[cfg(target_os = "macos")] - { - macKeyController - } - #[cfg(target_os = "windows")] - { - windowsKeyController - } - #[cfg(target_os = "linux")] - { - linuxKeyController - } - }; - - let key = match password { - Some(password) => key_manager.read_key(Some(&password), VIEW_KEY), - None => key_manager.read_key(None, VIEW_KEY), - }?; - - let viewing_key = match key { - Keys::ViewKey(v) => v, - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Invalid key type.".to_string(), - "Invalid key type.".to_string(), - )) - } - }; - - Ok(viewing_key) -} - -pub fn encrypt_with_password( - password: &str, - key: &Keys, -) -> AvailResult> { - match key { - PKey(private_key) => Ok(Encryptor::encrypt_private_key_with_secret( - &private_key, - password, - )?), - VKey(view_key) => Ok(Encryptor::encrypt_view_key_with_secret( - &view_key, password, - )?), - } -} - -pub fn encrypt_private_key_with_password( - password: &str, - private_key: &PrivateKey, -) -> AvailResult> { - Ok(Encryptor::encrypt_private_key_with_secret( - private_key, - password, - )?) -} - -pub fn encrypt_view_key_with_password( - password: &str, - view_key: &ViewKey, -) -> AvailResult> { - Ok(Encryptor::encrypt_view_key_with_secret(view_key, password)?) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn delete_util(password: &str) -> AvailResult { - let backup = get_backup_flag()?; - - let key_manager = { - #[cfg(target_os = "macos")] - { - macKeyController - } - #[cfg(target_os = "windows")] - { - windowsKeyController - } - #[cfg(target_os = "linux")] - { - linuxKeyController - } - }; - - let val: Identifier = Identifier::::from_str("test")?; - - match key_manager.delete_key(Some(password), val) { - Ok(_) => {} - Err(e) => {} - }; - - // delete encrypted data - drop_encrypted_data_table()?; - - // delete user preferences - delete_user_preferences()?; - - // delete tokens - drop_tokens_table()?; - - // if backup delete server side storage - if backup { - delete_all_server_storage().await?; - } - - // delete server user - delete_user().await?; - - Ok("Deleted.".to_string()) -} - -#[tauri::command(rename_all = "snake_case")] -pub fn delete_local_for_recovery(password: &str) -> AvailResult<()> { - let key_manager = { - #[cfg(target_os = "macos")] - { - macKeyController - } - #[cfg(target_os = "windows")] - { - windowsKeyController - } - #[cfg(target_os = "linux")] - { - linuxKeyController - } - }; - - let val: Identifier = Identifier::::from_str("test")?; - - match key_manager.delete_key(Some(password), val) { - Ok(_) => {} - Err(e) => {} - }; - - // delete encrypted data - drop_encrypted_data_table()?; - - // delete user preferences - delete_user_preferences()?; - - // delete tokens - drop_tokens_table()?; - - Ok(()) -} - -// Sign any string -pub fn sign_message( - message: &str, - password: Option, -) -> AvailResult<(Signature, Field)> { - let key = get_private_key::(password)?; - - let v_key = ViewKey::::try_from(key)?; - VIEWSESSION.set_view_session(&v_key.to_string())?; - - let rng = &mut rand::thread_rng(); - - let msg = utf8_string_to_bits(message); - let msg_field = N::hash_bhp512(&msg)?; - let msg = field_to_fields(&msg_field)?; - - let signature = key.sign(&msg, rng)?; - - Ok((signature, msg_field)) -} - -// Sign any string with provided private key -pub fn sign_message_w_key( - message: &str, - private_key: &PrivateKey, -) -> AvailResult<(Signature, Field)> { - let rng = &mut rand::thread_rng(); - - let msg = utf8_string_to_bits(message); - let msg_field = N::hash_bhp512(&msg)?; - let msg = field_to_fields(&msg_field)?; - - let signature = private_key.sign(&msg, rng)?; - - Ok((signature, msg_field)) -} - -mod test_utils { - use super::*; - use avail_common::models::constants::STRONG_PASSWORD; - use snarkvm::utilities::ToBytes; - - #[tokio::test] - async fn test_delete() { - delete_util(STRONG_PASSWORD).await.unwrap(); - } - - #[test] - fn test_several_pk_bytes() { - let pk1 = PrivateKey::::new(&mut rand::thread_rng()).unwrap(); - - let pk2 = PrivateKey::::new(&mut rand::thread_rng()).unwrap(); - - let pk1_bytes = pk1.to_bytes_le().unwrap(); - - let pk2_bytes = pk2.to_bytes_le().unwrap(); - - print!("PK1: {:?}", pk1_bytes); - print!("PK2 {:?}", pk2_bytes); - } -} diff --git a/backend/src/services/record_handling.rs b/backend/src/services/record_handling.rs deleted file mode 100644 index 60543f36..00000000 --- a/backend/src/services/record_handling.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod decrypt_transition; -pub mod records; -pub mod sync; -pub mod transfer; -pub mod utils; diff --git a/backend/src/services/record_handling/decrypt_transition.rs b/backend/src/services/record_handling/decrypt_transition.rs deleted file mode 100644 index 15aaa625..00000000 --- a/backend/src/services/record_handling/decrypt_transition.rs +++ /dev/null @@ -1,668 +0,0 @@ -use std::str::FromStr; - -use chrono::{DateTime, Local}; -use snarkvm::{ - prelude::{ - Ciphertext, Field, Group, Identifier, Input, Literal, Network, Output, Plaintext, - ProgramID, ToBits, Transition, ViewKey, U16, - }, - utilities::Uniform, -}; - -use super::utils::output_to_record_pointer; -use crate::{ - models::pointers::{ - record::AvailRecord, - transition::{TransitionPointer, TransitionType}, - }, - models::wallet_connect::records::{GetRecordsRequest, RecordFilterType, RecordsFilter}, - services::local_storage::{ - encrypted_data::store_encrypted_data, - storage_api::records::{ - get_record_pointers, get_record_pointers_ids, update_record_spent_local, - }, - }, -}; -use avail_common::{errors::AvailResult, models::encrypted_data::EncryptedData}; - -pub struct DecryptTransition {} - -impl DecryptTransition { - // Used to check if the user has executed the transition - pub fn owns_transition( - view_key: ViewKey, - tpk: Group, - tcm: Field, - ) -> AvailResult { - let scalar = *view_key; - let tvk = (tpk * scalar).to_x_coordinate(); - - //error == "Could not create transition commitment" - let tcm_derived = N::hash_psd2(&[tvk])?; - - Ok(tcm == tcm_derived) - } - - // used to check if user owns input or output ciphertext - // if it is an input - pub fn decrypt_ciphertext( - view_key: ViewKey, - ciphertext_str: &str, - tpk_str: &str, - program_id: &str, - function_name_str: &str, - index: usize, - ) -> AvailResult { - let tpk = Group::::from_str(tpk_str)?; - - //error == "Could not deserialize program_id" - let program_id = ProgramID::::from_str(program_id)?; - - //error == "Could not deserialize function name" - let function_name = Identifier::::from_str(function_name_str)?; - - let scalar = *view_key; - let tvk = (tpk * scalar).to_x_coordinate(); - - //error == "Could not create function id" - let function_id = N::hash_bhp1024( - &( - U16::::new(N::ID), - program_id.name(), - program_id.network(), - function_name, - ) - .to_bits_le(), - )?; - - let index_field = Field::from_u16(u16::try_from(index)?); - - //error == "Could not create ciphertext view key" - let ciphertext_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; - - //error == "Could not deserialize ciphertext" - let ciphertext = Ciphertext::::from_str(ciphertext_str)?; - - //error == "Could not decrypt ciphertext" - let plaintext = ciphertext.decrypt_symmetric(ciphertext_view_key)?; - - Ok(plaintext.to_string()) - } - - // Checks if the user sent inputs in the transiton or received ouputs from the transition - pub fn check_inputs_outputs_inclusion( - view_key: ViewKey, - transition: Transition, - transaction_id: N::TransactionID, - timestamp: DateTime, - block_height: u32, - message: Option, - from: Option, - ) -> AvailResult<(Vec>, Vec, Vec)> { - let address = view_key.to_address(); - let transition_id = transition.id(); - let function_name = transition.function_name().to_string(); - let program_id = transition.program_id().to_string(); - let scalar = *view_key; - let tvk = (*transition.tpk() * scalar).to_x_coordinate(); - - //filter - let filter = RecordsFilter::new( - vec![transition.program_id().to_string()], - None, - RecordFilterType::Unspent, - None, - ); - let get_records_request = GetRecordsRequest::new(None, Some(filter), None); - let (stored_record_pointers, ids) = get_record_pointers::(get_records_request)?; - - let function_id = N::hash_bhp1024( - &( - U16::::new(N::ID), - transition.program_id().name(), - transition.program_id().network(), - transition.function_name(), - ) - .to_bits_le(), - )?; - - let mut decrypted_inputs: Vec> = vec![]; - let mut encrypted_input_transition_pointers: Vec = vec![]; - let mut spent_input_ids: Vec = vec![]; - - let mut decrypted_outputs: Vec> = vec![]; - let mut encrypted_output_transition_pointers: Vec = vec![]; - - let mut record_pointers: Vec> = vec![]; - let mut amount = None; - - //check inputs - for (index, input) in transition.inputs().iter().enumerate() { - if let Input::Record(_id, _checksum) = input { - // spent records should be handled here - let input_tag = match input.tag() { - Some(tag) => tag, - None => continue, - }; - - for (record_pointer, id) in stored_record_pointers.iter().zip(ids.iter()) { - if &record_pointer.tag()? == input_tag { - update_record_spent_local::(id, true)?; - spent_input_ids.push(id.to_string()); - println!("================> INSIDE Input::Record"); - - let mock_input = - Input::::Public(Uniform::rand(&mut rand::thread_rng()), None); - decrypted_inputs.push(mock_input.clone()); - } - } - } else if let Input::Public(_plaintext_hash, Some(plaintext)) = input { - let plaintext_address = Plaintext::::Literal( - Literal::from_str(&address.to_string())?, - once_cell::sync::OnceCell::new(), - ); - - if plaintext == &plaintext_address { - let rng = &mut rand::thread_rng(); - - amount = find_amount_from_public_transfer(transition.inputs()); - - println!("Amount {:?}", amount); - //function is some public transfer to this address thus it is an Output tx - let mock_output = Output::::Public(Uniform::rand(rng), None); - - decrypted_outputs.push(mock_output); - } - } - } - - //check outputs - let num_inputs = transition.inputs().len(); - for (index, output) in transition.outputs().iter().enumerate() { - if let Output::Private(id, ciphertext_option) = output { - if let Some(ciphertext) = ciphertext_option { - let index_field = Field::from_u16(u16::try_from(num_inputs + index)?); - let output_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; - let plaintext = match ciphertext.decrypt_symmetric(output_view_key) { - Ok(plaintext) => plaintext, - Err(_) => { - continue; - } - }; - println!( - "================> INSIDE Output::Private ----> PlainText -- {:?}", - plaintext - ); - let output = Output::Public(*id, Some(plaintext)); - decrypted_outputs.push(output.clone()); - } - } else if let Output::Record(_id, _checksum, _record) = output { - let (record_pointer, found_amount) = output_to_record_pointer( - transaction_id, - transition_id.to_owned(), - transition.function_name(), - transition.program_id(), - output, - block_height, - view_key, - index, - )?; - - // println!("================> INSIDE Output::Record"); - match record_pointer { - Some(record_pointer) => { - record_pointers.push(record_pointer.clone()); - - let encrypted_record_pointer = record_pointer.to_encrypted_data(address)?; - store_encrypted_data(encrypted_record_pointer)?; - - decrypted_outputs.push(output.clone()); - println!("================> INSIDE record_pointer"); - } - None => continue, - } - - if let Some(found_amount) = found_amount { - //parse found amount from u64 - let found_amount_trimmed = found_amount.trim_end_matches("u64"); - let found_amount = found_amount_trimmed.parse::()? as f64 / 1000000.0; - - amount = Some(found_amount); - } - } - } - - if !decrypted_inputs.is_empty() { - // form transition pointer - let transition_pointer = TransitionPointer::new( - transition_id.to_owned(), - transaction_id, - program_id.clone(), - function_name.clone(), - timestamp, - TransitionType::Input, - message.clone(), - from.clone(), - amount, - block_height, - ); - println!("================> INSIDE !decrypted_inputs.is_empty()"); - - let encrypted_transition_pointer = transition_pointer.to_encrypted_data(address)?; - store_encrypted_data(encrypted_transition_pointer.clone())?; - encrypted_input_transition_pointers.push(encrypted_transition_pointer); - } - - if !decrypted_outputs.is_empty() { - // form transition pointer - let transition_pointer = TransitionPointer::new( - transition_id.to_owned(), - transaction_id, - program_id, - function_name, - timestamp, - TransitionType::Output, - message, - from, - amount, - block_height, - ); - println!("================> INSIDE !decrypted_outputs.is_empty()"); - let encrypted_transition_pointer = transition_pointer.to_encrypted_data(address)?; - store_encrypted_data(encrypted_transition_pointer.clone())?; - - encrypted_output_transition_pointers.push(encrypted_transition_pointer); - } - - // combine encrypted transition pointers - let mut encrypted_transition_pointers: Vec = vec![]; - encrypted_transition_pointers.append(&mut encrypted_input_transition_pointers); - encrypted_transition_pointers.append(&mut encrypted_output_transition_pointers); - - Ok(( - record_pointers, - encrypted_transition_pointers, - spent_input_ids, - )) - } - - pub fn decrypt_transition( - view_key: ViewKey, - transition_str: &str, - ) -> AvailResult { - let transition: Transition = serde_json::from_str(transition_str)?; - - let scalar = *view_key; - let tvk = (*transition.tpk() * scalar).to_x_coordinate(); - - let function_id = N::hash_bhp1024( - &( - U16::::new(N::ID), - transition.program_id().name(), - transition.program_id().network(), - transition.function_name(), - ) - .to_bits_le(), - )?; - - let mut decrypted_inputs: Vec> = vec![]; - let mut decrypted_outputs: Vec> = vec![]; - - for (index, input) in transition.inputs().iter().enumerate() { - if let Input::Private(id, Some(ciphertext)) = input { - let index_field = Field::from_u16(u16::try_from(index)?); - let input_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; - let plaintext = ciphertext.decrypt_symmetric(input_view_key)?; - decrypted_inputs.push(Input::Public(*id, Some(plaintext))); - } else { - decrypted_inputs.push(input.clone()); - } - } - - let num_inputs = transition.inputs().len(); - for (index, output) in transition.outputs().iter().enumerate() { - if let Output::Private(id, Some(ciphertext)) = output { - let index_field = Field::from_u16(u16::try_from(num_inputs + index)?); - let output_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; - let plaintext = ciphertext.decrypt_symmetric(output_view_key)?; - decrypted_outputs.push(Output::Public(*id, Some(plaintext))); - } else { - decrypted_outputs.push(output.clone()); - } - } - - let decrypted_transition = Transition::::new( - *transition.program_id(), - *transition.function_name(), - decrypted_inputs, - decrypted_outputs, - *transition.tpk(), - *transition.tcm(), - )?; - - let transition_output = serde_json::to_string(&decrypted_transition)?; - - Ok(transition_output) - } - - pub fn decrypt_inputs_outputs( - view_key: ViewKey, - transition: &Transition, - ) -> AvailResult<(Vec, Vec)> { - let scalar = *view_key; - let tvk = (*transition.tpk() * scalar).to_x_coordinate(); - - let function_id = N::hash_bhp1024( - &( - U16::::new(N::ID), - transition.program_id().name(), - transition.program_id().network(), - transition.function_name(), - ) - .to_bits_le(), - )?; - - let mut decrypted_inputs: Vec = vec![]; - let mut decrypted_outputs: Vec = vec![]; - - let (stored_record_pointers, _ids) = get_record_pointers_ids::()?; - - for (index, input) in transition.inputs().iter().enumerate() { - if let Input::Private(_id, ciphertext_option) = input { - if let Some(ciphertext) = ciphertext_option { - let index_field = Field::from_u16(u16::try_from(index)?); - - let input_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; - let input_str = match ciphertext.decrypt_symmetric(input_view_key) { - Ok(plaintext) => plaintext.to_string(), - Err(_) => ciphertext.to_string(), - }; - - decrypted_inputs.push(input_str); - } else { - decrypted_inputs.push(input.to_string()); - } - } else if let Input::Record(_serial_number, tag) = input { - for record_pointer in stored_record_pointers.iter() { - if &record_pointer.tag()? == tag { - let record = record_pointer.to_record()?; - decrypted_inputs.push(record.to_string()); - } - } - } else if let Input::Public(_plaintext_hash, plaintext) = input { - if let Some(plaintext) = plaintext { - decrypted_inputs.push(plaintext.to_string()); - } - } else if let Input::Constant(_plaintext_hash, plaintext) = input { - if let Some(plaintext) = plaintext { - decrypted_inputs.push(plaintext.to_string()); - } - } else if let Input::ExternalRecord(_input_commitent) = input { - //handle external record input - } - } - - let num_inputs = transition.inputs().len(); - for (index, output) in transition.outputs().iter().enumerate() { - if let Output::Private(_id, ciphertext_option) = output { - if let Some(ciphertext) = ciphertext_option { - let index_field = Field::from_u16(u16::try_from(num_inputs + index)?); - - let output_view_key = N::hash_psd4(&[function_id, tvk, index_field])?; - let output_str = match ciphertext.decrypt_symmetric(output_view_key) { - Ok(plaintext) => plaintext.to_string(), - Err(_) => ciphertext.to_string(), - }; - - decrypted_outputs.push(output_str); - } else { - decrypted_outputs.push(output.to_string()); - } - } else if let Output::Record(_commitment, _checksum, ciphertext) = output { - match ciphertext { - Some(ciphertext) => { - // do i own this output? - let record = match ciphertext.decrypt(&view_key) { - Ok(plaintext) => plaintext.to_string(), - Err(_) => ciphertext.to_string(), - }; - - decrypted_outputs.push(record); - } - None => { - decrypted_outputs.push(output.to_string()); - } - } - } else if let Output::Public(_plaintext_hash, plaintext) = output { - if let Some(_plaintext) = plaintext { - decrypted_outputs.push(output.to_string()); - } - } else if let Output::Future(_future_hash, future) = output { - if let Some(future) = future { - decrypted_outputs.push(future.to_string()); - } - } else if let Output::Constant(_plaintext_hash, plaintext) = output { - if let Some(plaintext) = plaintext { - decrypted_outputs.push(plaintext.to_string()); - } - } else { - decrypted_outputs.push(output.to_string()); - } - } - Ok((decrypted_inputs, decrypted_outputs)) - } -} - -pub fn find_amount_from_public_transfer(inputs: &[Input]) -> Option { - for input in inputs { - print!("{:?}", input); - if let Input::Public(_plaintext_hash, Some(Plaintext::Literal(Literal::U64(amount), _))) = - input - { - print!("{:?}", amount); - return Some(**amount as f64 / 1000000.0); - } - } - None -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - - use snarkvm::console::network::Testnet3; - use snarkvm::prelude::PrivateKey; - - use super::*; - use avail_common::models::constants::*; - - const VIEW_KEY: &str = "AViewKey1nPQW8P83ajkMBHQwYjbUfjGHVSkBQ5wctpJJmQvW1SyZ"; - const INCORRECT_VIEW_KEY: &str = "AViewKey1o8Hqq4tVbVMeeGtkEGUR7ULghFN8j89sqNQKYRZfe21u"; - const TRANSITION_VIEW_KEY: &str = "AViewKey1mSnpFFC8Mj4fXbK5YiWgZ3mjiV8CxA79bYNa8ymUpTrw"; - const TRANSITION: &str = r#" - { - "id": "as1pe954nkrsz4ztq7tphfug0cxtk4t0v5nnh885llkxufkckc0pcqq64fdjh", - "program": "credits.aleo", - "function": "transfer", - "inputs": [ - { - "type": "record", - "id": "7627242362896255517779759121644670167065542804779447008052019369271498021878field", - "tag": "7326825649979738473754819542510294000608550604334299567498630301585328020355field" - }, - { - "type": "private", - "id": "5890350227539634203276798567594921209939645071583932668707733854543695228358field", - "value": "ciphertext1qgqz2ypza9srfjnncjzz3hegltwmk0y348ufmklcuqwep2u9wnsqwqkrgx49dn0x78uqypznmyv8r80zwkte9rkfucv7fk4hw7w5s86dzyjmktp7" - }, - { - "type": "private", - "id": "3523824429192332435402492789955521910058950257573863610460494169456702420796field", - "value": "ciphertext1qyqfuz7006rcq9utzdsthdxqv4ra59u58wuggcacv44ka5uv7gyjcrsfh5xwh" - } - ], - "outputs": [ - { - "type": "record", - "id": "8375863992930925508608168893083821026035462437311607208725719081756051927038field", - "checksum": "327996249778261324588393772992776501551729208590293775377741829891566277743field", - "value": "record1qyqsqv0te3n9fws54jjywmrp36lc8l5gxgzyc9anjk30qsf7h45nfvgpqyxx66trwfhkxun9v35hguerqqpqzq8hd7es9dptx8l6ldn7u536g3hefvl03e6ztrufgk97ekf0us6azgl65lhfgcm4jf7fua2pcc2asy7r46rzv7eefvc8yrs39sgadue3zkl3emg" - }, - { - "type": "record", - "id": "3831168224702324801478452706121992429555677457517630037556628292830553507758field", - "checksum": "104402939347002555939092140274082734465350067270030368157770539944634402431field", - "value": "record1qyqspsy0qghu8wqmf8wq2w4ccqqg8zsgxc3ge2znf4uklh8tutq2swgqqyxx66trwfhkxun9v35hguerqqpqzq9c6u30j7srax79wdvdqt2ytpne4vyvae6z9fq85rs09nj2f72uqm0kn9tx5t3znnj7hrqffzdcquacgyrqdfuuum2km7wvxcmy258svvkjzsh" - } - ], - "proof": "proof1qqqqzqqqqqqqqqqqjgn70r0h5xcsysua8uve5wk400ash3ry6dwr3jjmeft5dmmql03ju0memtrwzppfsyl9x25v6svgrled6hd4s2887yz6wdde7fmv3kwlrdjx8kpvzq5asy02sljyc87ya7me3h5nkh3davwqklw6m2qzszt850x7jq0kt45zghwah6kalw7ufdh2v83jcrcwcpcwwa0m44sestdagm0z7hqe20zlfszva22kfqgpvnj9mavgqw2v5rmeeyz8hmn2j29npkvgteg0447zh6c097tx4dr2vmu2n5ts67xqu83058sjus3srrdgcypql8mymv7rhg580m5gckc4vnwjm2a53vg9sgqmyahs4fhmm0t0atyp9gjvflpt76d2nnsaqyqntm08rmtg0mwzajy2lpyfgq0r0gwq6pqcraty4623uyrzz8036np4clx3ak54qdlfamprav0chq95d696hsy4sdpsfphxuzq5mmehl0pjgk3f7wuvtjshz9dyrnrcwggnmjdqw965fmnjhlxv86ddruqj3cur9r38g2v4evaf2n5clr0844aek7j2gvz4zgshfddlkrg92wzk4yfwdjrwuvmpv77ss2f3efypelqu8sjp23fk93ygdads9lqtz8ghggdy5uhe9j7cyrg2ug4ghww9vvfljk2rgk04sfm23n8j474gzsmzz0nptrtdqmr2afddp5acssa5twxlcpf6vcghssrdan52wrykz5evryzvarw0xj9y0zf2ddarqxqfv2rcjfey9ur7tmaeh2qvqv8z9ggg8vtajql6vj2vuw5shmxsjahcq2ve7m3m3s8a30vy0qx47u263g77hz448mxug4r99vfgkpggv7rysklv0e9l40nt20uvnkuepeftgqwlz7t436z93fpq5qadxsr2tl93t87czw68h6nsglh9xxnenasa2f68vl7pvqahnjlyatcvzyytqxrglvgax9525hwvn939k9jtxzjeh97chr07qgvsp6f007c3p7hdca6cm7ss7wmdrefehzzpj4rpj30cnu2rhdce35ku3y640avsxlujsxnfs69g32q3nlqe7tlcka9zkmeurxx3fcq054sseehe2kqjr2tfdwmgfzgj28vynw4nxq54pvmpgkj53asfnt25yz250lmx0vzqyqqqqqqqqqqq9c4hem5wef967dqy4spcypsr8kwhnmxp35zlrdgq6rwejyqej2l2h6w2lnc7ttw2qxlj8shfju5czqwrcnaj00ky0yc98jck2rk43upw4gzxk6l866n0mh68q0vjalg0qd7tvlu4an04s3u799u28vct6wwm2gn0r5lpcv5jttds6ffw6ykkq6g42yvlam6zreceeqwqz25mrqqqqqppqwa5", - "tpk": "853764860907185272244987221391264508066723405990098126446569313951469774602group", - "tcm": "2890501131780933954363007654088502278361631362478553633880506988907453958068field" - } - "#; - const TRANSITION2: &str = r#" - { - "id":"au12llfye62hrxva7kdtk6c8qjff5w06pys77qaf74yvk8nm36pcvzqzhnyqk", - "program":"credits.aleo", - "function":"transfer_public_to_private", - "inputs":[ - { - "type":"private", - "id":"8304400100965833495700876350325817857909709976454835525511070424468112487393field", - "value":"ciphertext1qgqqra9lu5kxlcyantu9m62y64q6a6lqnpwnjhw7sfhzpvfs3xfrkzvd3f8y43ayxvg06m0jdy5mygzkq5xtzhesnaevv2sevtrr8tlups2ylg7q" - }, - { - "type":"public", - "id":"4284736765818567156746053297849217056635200819021601944769636535729298276732field", - "value":"10000u64" - } - ], - "outputs":[ - { - "type":"record", - "id":"7700798280026244642782503068152162345162841409942906121174875714371266381229field", - "checksum":"6815669942399919593565610266251968344648606815539211826018363024847516584293field", - "value":"record1qyqsqyqj75z6agymcp8n3zc3vdt79flrvmkntw3x3ns9r62cajs28rs9qyxx66trwfhkxun9v35hguerqqpqzq82x8jygs6uu3xv5vvsfqmhxwp0mgd6cp94s9tltctq6k7kfk5xp6f70g4ehp4cu3uky7gt7dsfe5lxgg9v8f89zfqhckxdy4fjlt3sgeectyv"}, - { - "type":"future", - "id":"7497616154742727853190695963847945689716274231039404007173109580428445795806field", - "value":"{\n program_id: credits.aleo,\n function_name: transfer_public_to_private,\n arguments: [\n aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px,\n 10000u64\n ]\n}"}], - "tpk":"7536197841680445770427840516566211501284881266835565366311996370053681646595group", - "tcm":"5280795820292733910634681057195416067603461129653774341851374878700562172179field" - } - "#; - - #[test] - fn test_decrypt_transition() { - let private_key = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let view_key = ViewKey::::try_from(private_key).unwrap(); - - let decrypted_transition_str = - DecryptTransition::decrypt_transition(view_key, TRANSITION2).unwrap(); - - let decrypted_transition: Transition = - serde_json::from_str(&decrypted_transition_str.clone()).unwrap(); - - println!("Decrypted Transition {:?}", decrypted_transition); - let public_input = decrypted_transition - .inputs() - .into_iter() - .skip(1) - .next() - .unwrap(); - /* - if let Input::Public(_id, plaintext_option) = public_input { - let plaintext = plaintext_option.as_ref().unwrap(); - assert_eq!( - plaintext.to_string(), - "aleo146dx5e4nssf49t0aq9qljk474kqxk848tl05m8w84vc0jqa30spqf4me04" - ); - } else { - panic!("Expected public input"); - } - */ - // let public_output = decrypted_transition.outputs().into_iter().next().unwrap(); - - // if let Output::Public(_id, plaintext_option) = public_output { - // let plaintext = plaintext_option.as_ref().unwrap(); - // assert_eq!(plaintext.to_string(), "100000000u64"); - // } else { - // panic!("Expected public output"); - // } - } - - fn test_decrypt_ciphertext_input() { - let view_key = ViewKey::::from_str(VIEW_KEY).unwrap(); - - // Try decrypting private input - let plaintext = DecryptTransition::decrypt_ciphertext( - view_key, - "ciphertext1qyq2786j69kjqmwz7lk9cn3glyq2w34j6zhlvxum6u9xkfk76hmd2rgg34kev", - "3681563105640905751787370687361466941855498391730203508101562167054325552256group", - "helloworld.aleo", - "main", - 1, - ) - .unwrap(); - - assert_eq!(plaintext, "2u32"); - } - - #[test] - fn test_decrypt_ciphertext_output() { - let view_key = ViewKey::::from_str(VIEW_KEY).unwrap(); - - // Try decrypting private output - let plaintext = DecryptTransition::decrypt_ciphertext( - view_key, - "ciphertext1qyqw68078jwlvz6v2wynue3g3dndyv0ydqutlmn99sfashquhkf52zql6xu7r", - "3681563105640905751787370687361466941855498391730203508101562167054325552256group", - "helloworld.aleo", - "main", - 2, - ) - .unwrap(); - - assert_eq!(plaintext, "3u32"); - } - - #[test] - fn test_owns_transition_true() { - let view_key = ViewKey::::from_str(VIEW_KEY).unwrap(); - - let owns_transition = DecryptTransition::owns_transition( - view_key, - Group::::from_str( - "3681563105640905751787370687361466941855498391730203508101562167054325552256group", - ) - .unwrap(), - Field::::from_str( - "3205548165782039452146864733009325261935114902820697593223360259711032449007field", - ) - .unwrap(), - ) - .unwrap(); - - assert!(owns_transition); - } - - #[test] - fn test_owns_transition_false() { - let view_key = ViewKey::::from_str(INCORRECT_VIEW_KEY).unwrap(); - - let owns_transition = DecryptTransition::owns_transition( - view_key, - Group::::from_str( - "3681563105640905751787370687361466941855498391730203508101562167054325552256group", - ) - .unwrap(), - Field::::from_str( - "3205548165782039452146864733009325261935114902820697593223360259711032449007field", - ) - .unwrap(), - ) - .unwrap(); - - assert!(!owns_transition); - } -} diff --git a/backend/src/services/record_handling/docs.md b/backend/src/services/record_handling/docs.md deleted file mode 100644 index 371f40d6..00000000 --- a/backend/src/services/record_handling/docs.md +++ /dev/null @@ -1,4 +0,0 @@ -# Notes on Record Handling - -## The tag system -`tag` construction, the `tag` is not stored with the record as tag but can be computed via `N::hash_psd2(&[sk_tag, commitment])` as we do where `sk_tag` can only be derived from your `view_key` , and then the tag is stored on chain when this record is spent so you can literally query a block for all the tags it stores and these would be all the tags of records spent within that block. But you cannot check if a specific record has been spent without the viewing key. diff --git a/backend/src/services/record_handling/records.rs b/backend/src/services/record_handling/records.rs deleted file mode 100644 index f59c734d..00000000 --- a/backend/src/services/record_handling/records.rs +++ /dev/null @@ -1,800 +0,0 @@ -use chrono::Local; -use snarkvm::{ - console::program::Itertools, - prelude::{ConfirmedTransaction, Network, Plaintext, Record}, -}; -use std::ops::Sub; -use tauri::{Manager, Window}; - -use crate::{ - api::aleo_client::{setup_client, setup_local_client}, - helpers::utils::get_timestamp_from_i64, - models::wallet_connect::records::{GetRecordsRequest, RecordFilterType, RecordsFilter}, - services::{ - local_storage::{ - encrypted_data::{ - handle_block_scan_failure, update_encrypted_transaction_confirmed_by_id, - update_encrypted_transaction_state_by_id, - }, - persistent_storage::{get_address_string, update_last_sync}, - session::view::VIEWSESSION, - storage_api::{ - deployment::{find_encrypt_store_deployments, get_deployment_pointer}, - records::{get_record_pointers, get_record_pointers_for_record_type}, - transaction::{ - check_unconfirmed_transactions, get_transaction_pointer, get_tx_ids_from_date, - get_unconfirmed_and_failed_transaction_ids, - }, - }, - }, - record_handling::utils::{ - get_executed_transitions, handle_deployment_confirmed, handle_deployment_rejection, - handle_transaction_confirmed, handle_transaction_rejection, input_spent_check, - sync_transaction, transition_to_record_pointer, - }, - }, -}; - -use avail_common::{ - aleo_tools::program_manager::Credits, - errors::{AvailError, AvailErrorType, AvailResult}, - models::encrypted_data::{EncryptedData, RecordTypeCommon, TransactionState}, -}; - -/// Scans the blockchain for new records, distills record pointers, transition pointer and tags, and returns them -pub fn get_records( - last_sync: u32, - height: u32, - window: Option, -) -> AvailResult { - let view_key = VIEWSESSION.get_instance::()?; - let address = view_key.to_address(); - - let api_client = setup_client::()?; - - let step_size = 49; - - let latest_height = height; - - let last_sync_block = api_client.get_block(last_sync)?; - let last_sync_timestamp = get_timestamp_from_i64(last_sync_block.timestamp())?; - - // checks if unconfirmed transactions have expired and updates their state to failed - check_unconfirmed_transactions::()?; - - let stored_transaction_ids = get_tx_ids_from_date::(last_sync_timestamp)?; - - println!("Stored transaction ids: {:?}", stored_transaction_ids); - - let unconfirmed_and_failed_ids = get_unconfirmed_and_failed_transaction_ids::()?; - - println!( - "Unconfirmed and failed ids: {:?}", - unconfirmed_and_failed_ids - ); - - let unconfirmed_and_failed_transaction_ids = unconfirmed_and_failed_ids - .iter() - .map(|(id, _)| *id) - .collect::>(); - - let stored_transaction_ids = stored_transaction_ids - .iter() - .filter(|id| !unconfirmed_and_failed_transaction_ids.contains(id)) - .cloned() - .collect_vec(); - - println!( - "Stored transaction ids without unconfirmed and failed: {:?}", - stored_transaction_ids - ); - - let mut end_height = last_sync.saturating_add(step_size); - let mut start_height = last_sync; - - if end_height > latest_height { - end_height = latest_height; - } - - let mut found_flag = false; - - for _ in (last_sync..latest_height).step_by(step_size as usize) { - let mut blocks = api_client.get_blocks(start_height, end_height)?; - - for block in blocks { - // Check for deployment transactions - let transactions = block.transactions(); - let timestamp = get_timestamp_from_i64(block.clone().timestamp())?; - let height = block.height(); - - match find_encrypt_store_deployments( - transactions, - height, - timestamp, - address, - stored_transaction_ids.clone(), - ) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error scanning deployment transactions.".to_string(), - )); - } - } - - for transaction in transactions.iter() { - let transaction_id = transaction.id(); - - let unconfirmed_transaction_id = match transaction.to_unconfirmed_transaction_id() { - Ok(id) => id, - Err(_) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::SnarkVm, - "Error getting unconfirmed transaction id".to_string(), - "Issue getting unconfirmed transaction id".to_string(), - )); - } - }; - - if stored_transaction_ids.contains(&transaction_id) - || stored_transaction_ids.contains(&unconfirmed_transaction_id) - { - continue; - } - - if let Some((tx_id, pointer_id)) = - unconfirmed_and_failed_ids.iter().find(|(tx_id, _)| { - tx_id == &transaction_id || tx_id == &unconfirmed_transaction_id - }) - { - let inner_tx = transaction.transaction(); - let fee = match inner_tx.fee_amount() { - Ok(fee) => *fee as f64 / 1000000.0, - Err(_) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::SnarkVm, - "Error calculating fee".to_string(), - "Issue calculating fee".to_string(), - )); - } - }; - - if let ConfirmedTransaction::::AcceptedExecute(_, _, _) = transaction { - let executed_transitions = - match get_executed_transitions::(inner_tx, height) { - Ok(transitions) => transitions, - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::SnarkVm, - e.to_string(), - "Error getting executed transitions".to_string(), - )); - } - }; - - match handle_transaction_confirmed( - pointer_id.as_str(), - *tx_id, - executed_transitions, - height, - timestamp, - Some(fee), - address, - ) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error handling confirmed transaction".to_string(), - )); - } - }; - - continue; - } else if let ConfirmedTransaction::::AcceptedDeploy(_, _, _) = transaction { - if let Some(fee_transition) = transaction.fee_transition() { - let transition = fee_transition.transition(); - - match input_spent_check(transition, true) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error checking spent input".to_string(), - )); - } - }; - - match transition_to_record_pointer( - *tx_id, - transition.clone(), - height, - view_key, - ) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error finding records from transition".to_string(), - )); - } - }; - } - - match handle_deployment_confirmed( - pointer_id.as_str(), - *tx_id, - height, - Some(fee), - address, - ) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error handling confirmed deployment".to_string(), - )); - } - }; - - continue; - } else if let ConfirmedTransaction::::RejectedDeploy(_, fee_tx, _, _) = - transaction - { - let deployment_pointer = - match get_deployment_pointer::(pointer_id.as_str()) { - Ok(pointer) => pointer, - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error getting deployment pointer".to_string(), - )); - } - }; - - if let Some(fee_transition) = fee_tx.fee_transition() { - let transition = fee_transition.transition(); - - match input_spent_check(transition, true) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error checking spent input".to_string(), - )); - } - }; - - match transition_to_record_pointer( - *tx_id, - transition.clone(), - height, - view_key, - ) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error finding records from transition".to_string(), - )); - } - }; - } - - match handle_deployment_rejection( - deployment_pointer, - pointer_id.as_str(), - *tx_id, - height, - Some(fee), - address, - ) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error handling rejected deployment".to_string(), - )); - } - }; - - continue; - } else if let ConfirmedTransaction::::RejectedExecute( - _, - fee_tx, - rejected_tx, - _, - ) = transaction - { - let transaction_pointer = - match get_transaction_pointer::(pointer_id.as_str()) { - Ok(pointer) => pointer, - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error getting transaction pointer".to_string(), - )); - } - }; - - if let Some(fee_transition) = fee_tx.fee_transition() { - let transition = fee_transition.transition(); - - match input_spent_check(transition, true) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error checking spent input".to_string(), - )); - } - }; - - match transition_to_record_pointer( - *tx_id, - transition.clone(), - height, - view_key, - ) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error finding records from transition".to_string(), - )); - } - }; - } - - if let Some(rejected_execution) = rejected_tx.execution() { - match handle_transaction_rejection( - transaction_pointer, - pointer_id.as_str(), - Some(rejected_execution.clone()), - Some(*tx_id), - height, - Some(fee), - address, - ) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error handling rejected transaction".to_string(), - )); - } - }; - - continue; - } - - match handle_transaction_rejection( - transaction_pointer, - pointer_id.as_str(), - None, - Some(*tx_id), - height, - Some(fee), - address, - ) { - Ok(_) => {} - Err(e) => { - handle_block_scan_failure::(height)?; - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error handling rejected transaction".to_string(), - )); - } - }; - - continue; - } - continue; - } - - let (_, _, _, bool_flag) = - match sync_transaction::(transaction, height, timestamp, None, None) { - Ok(transaction_result) => transaction_result, - Err(e) => { - match handle_block_scan_failure::(height) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error syncing transaction".to_string(), - )); - } - } - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error syncing transaction".to_string(), - )); - } - }; - - if !found_flag { - found_flag = bool_flag; - } - } - - match update_last_sync(height) { - Ok(_) => { - println!("Synced {}", height); - } - Err(e) => { - match handle_block_scan_failure::(height) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error syncing transaction".to_string(), - )); - } - } - - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error updating last synced block height".to_string(), - )); - } - }; - } - - let percentage = (((end_height - last_sync) as f32 / (latest_height - last_sync) as f32) - * 10000 as f32) - .round() - / 100.0; - - let percentage = if percentage > 100.0 { - 100.0 - } else { - percentage - }; - - println!("{}% of blocks scanned", percentage); - - // update progress bar - if let Some(window) = window.clone() { - match window.emit("scan_progress", percentage) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error updating progress bar".to_string(), - )); - } - }; - } - - // Search in reverse order from the latest block to the earliest block - start_height = end_height + 1; - end_height = start_height.saturating_add(step_size); - if end_height > latest_height { - end_height = latest_height; - }; - } - - Ok(found_flag) -} - -/// Fetches an aleo credits record to spend -pub fn find_aleo_credits_record_to_spend( - amount: &u64, - previous: Vec, -) -> AvailResult<(Record>, String, String)> { - let address = get_address_string()?; - let (record_pointers, encrypted_record_ids) = - get_record_pointers_for_record_type::(RecordTypeCommon::AleoCredits, &address)?; - - let mut iter = 0; - let mut balance_counter = 0u64; - - for record in record_pointers.iter() { - if record.metadata.spent { - iter += 1; - continue; - } - if previous.clone().contains(&record.metadata.nonce) { - iter += 1; - continue; - } - - let aleo_record = record.to_record()?; - let record_amount = aleo_record.microcredits()?; - - if &record_amount >= amount { - return Ok(( - aleo_record, - record.pointer.commitment.clone(), - encrypted_record_ids[iter].clone(), - )); - } - - iter += 1; - balance_counter += record_amount; - } - - // TODO - implement join_n - if &balance_counter > amount { - return Err(AvailError::new( - AvailErrorType::Internal, - "Join aleo credit records to obtain a sufficient balance.".to_string(), - "Join aleo credit records to obtain a sufficient balance.".to_string(), - )); - } - - Err(AvailError::new( - AvailErrorType::Internal, - "Not enough balance".to_string(), - "Not enough balance".to_string(), - )) - - // find first record that satisfies the amount required -} - -pub fn find_tokens_to_spend( - asset_id: &str, - amount: &u64, - previous: Vec, -) -> AvailResult<(Record>, String, String)> { - let _address = get_address_string()?; - let program_id = format!("{}{}", asset_id, ".aleo"); - let record_name = format!("{}{}", asset_id, ".record"); - - let filter = RecordsFilter::new( - vec![program_id.to_string()], - None, - RecordFilterType::Unspent, - Some(record_name.to_string()), - ); - let get_records_request = GetRecordsRequest::new(None, Some(filter), None); - let (record_pointers, ids) = get_record_pointers::(get_records_request)?; - - let mut iter = 0; - let mut balance_counter = 0u64; - - for record in record_pointers.iter() { - if record.metadata.spent { - iter += 1; - continue; - } - if previous.clone().contains(&record.metadata.nonce) { - iter += 1; - continue; - } - - let aleo_record = record.to_record()?; - let record_amount = aleo_record.microcredits()?; - - if &record_amount >= amount { - return Ok(( - aleo_record, - record.pointer.commitment.clone(), - ids[iter].clone(), - )); - } - - iter += 1; - balance_counter += record_amount; - } - - // TODO - implement join_n - if &balance_counter > amount { - return Err(AvailError::new( - AvailErrorType::Internal, - "Join token records to obtain a sufficient balance.".to_string(), - "Join token records to obtain a sufficient balance.".to_string(), - )); - } - - Err(AvailError::new( - AvailErrorType::Internal, - "Not enough balance".to_string(), - "Not enough balance".to_string(), - )) - - // find first record that satisfies the amount required -} - -///Joins two records together -/// TODO - Join n records to meet amount x -/* -async fn join_records( - pk: PrivateKey, - amount: u64, - token: &str, -) -> AvailResult { - let fee = 10000u64; - - let fee_record = find_aleo_credits_record_to_spend::(fee, vec![])?; - - // TODO - iteratively find records until amount is satisfied - - - let inputs: Vec> = vec![Value::Record(input_record), Value::Record(input2_record)]; - - let api_client = AleoAPIClient::::local_testnet3("3030"); - let mut program_manager = - ProgramManager::::new(Some(pk), None, Some(api_client), None).unwrap(); - - //calculate estimate - - let join_execution = program_manager.execute_program( - "credits.aleo", - "join", - inputs.iter(), - fee, - fee_record, - None, - )?; - - update_identifier_status(fee_commitment, &fee_id).await?; - update_identifier_status(input_commitment, &input_id).await?; - update_identifier_status(input2_commitment, &input2_id).await?; - - //check tx block, normal post tx procedure - Ok(join_execution) -} -*/ - -///Splits a record into two records -/* -async fn split_records( - pk: PrivateKey, - amount: u64, - token: &str, -) -> AvailResult { - let fee = 10000u64; - - let fee_record = find_aleo_credits_record_to_spend::(fee, vec![])?; - - let input_record = find_aleo_credits_record_to_spend::(amount, vec![])?; - - let inputs: Vec> = vec![Value::Record(input_record)]; - - let api_client = AleoAPIClient::::local_testnet3("3030"); - let mut program_manager = - ProgramManager::::new(Some(pk), None, Some(api_client), None).unwrap(); - - let split_execution = program_manager.execute_program( - "credits.aleo", - "split", - inputs.iter(), - fee, - fee_record, - None, - )?; - - //TODO - How to get commitment from record - - update_identifier_status(fee_record.to_commitment(program_id, record_name), &fee_id).await?; - update_identifier_status(input_commitment, &input_id).await?; - - Ok(split_execution) -} -*/ - -#[cfg(test)] -mod record_handling_test { - use super::*; - use crate::services::local_storage::persistent_storage::get_last_sync; - use snarkvm::prelude::{AleoID, Field, Testnet3}; - use std::str::FromStr; - - #[test] - fn test_get_transaction() { - let start = 500527u32; - let end = 500531u32; - - let api_client = setup_client::().unwrap(); - - let blocks = api_client.get_blocks(start, end).unwrap(); - - let tx_id = &AleoID::, 29793>::from_str( - "at1w8t8pkc9xuf2p05gp9fanxpx0h53jmpguc07ja34s3jm905v65gss306rr", - ); - - for block in blocks { - let transactions = block.transactions(); - - match tx_id { - Ok(tx_id) => { - let tx = transactions.get(tx_id); - let info = match tx { - Some(tx) => tx, - None => { - println!("tx not found"); - continue; - } - }; - println!("info: {:?}", info); - } - Err(e) => { - print!("{}", e.to_string()) - } - } - } - } - - /* - #[test] - fn test_nova() { - let _res = get_nova_records::(372243).unwrap(); - - println!("res: {:?}", _res); - } - */ - - #[test] - fn test_get_records() { - let api_client = setup_client::().unwrap(); - - let latest_height = api_client.latest_height().unwrap(); - let last_sync = get_last_sync().unwrap(); - - let _res = get_records::(last_sync, latest_height, None).unwrap(); - - println!("res: {:?}", _res); - } - - #[test] - fn find_aleo_credits_record_to_spend_test() { - let _res = find_aleo_credits_record_to_spend::(&10000, vec![]).unwrap(); - - println!("res: {:?}", _res); - } -} diff --git a/backend/src/services/record_handling/sync.rs b/backend/src/services/record_handling/sync.rs deleted file mode 100644 index 8c646dc4..00000000 --- a/backend/src/services/record_handling/sync.rs +++ /dev/null @@ -1,805 +0,0 @@ -use snarkvm::prelude::*; -use tauri::Window; -use uuid::Uuid; - -use crate::{ - api::{ - aleo_client::{setup_client, setup_local_client}, - encrypted_data::{ - delete_invalid_transactions_in, get_new_transaction_messages, post_encrypted_data, - synced, - }, - }, - helpers::utils::get_timestamp_from_i64_utc, - models::event::TxScanResponse, - models::pointers::message::TransactionMessage, - services::local_storage::{ - encrypted_data::{ - get_encrypted_data_to_backup, get_encrypted_data_to_update, - update_encrypted_data_synced_on_by_id, - }, - storage_api::records::{encrypt_and_store_records, update_records_spent_backup}, - }, -}; - -use std::str::FromStr; - -use avail_common::{ - errors::{AvailError, AvailErrorType, AvailResult}, - models::{encrypted_data::EncryptedData, network::SupportedNetworks}, -}; - -use crate::services::local_storage::persistent_storage::{ - get_address, get_backup_flag, get_last_backup_sync, get_last_sync, get_network, - update_last_backup_sync, -}; - -use super::{records::get_records, utils::sync_transaction}; - -/// processes transactions into record and transition pointers and stores them -fn process_transaction( - transaction_message: &TransactionMessage, - address: Address, - id: Uuid, -) -> AvailResult<(Vec, Vec, Option)> { - let (transaction, timestamp) = transaction_message.verify()?; - - if let Some(transaction) = transaction { - println!("Transaction verified"); - let (_, record_pointers, encrypted_transitions, _) = sync_transaction( - &transaction, - transaction_message.confirmed_height(), - timestamp, - transaction_message.message(), - Some(transaction_message.from()), - )?; - println!("{:?}", record_pointers); - let encrypted_records = encrypt_and_store_records(record_pointers, address)?; - Ok((encrypted_records, encrypted_transitions, None)) - } else { - println!("Transaction failed verification"); - Ok((vec![], vec![], Some(id))) - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn txs_sync() -> AvailResult { - let network = get_network()?; - - let transactions = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => txs_sync_raw::().await?, - _ => txs_sync_raw::().await?, //SupportedNetworks::Devnet => txs_sync_raw::().await?, - //SupportedNetworks::Mainnet => txs_sync_raw::().await?, - }; - - Ok(transactions) -} - -/// syncs transactions sent to user by another avail user -pub async fn txs_sync_raw() -> AvailResult { - let api_client = setup_client::()?; - - let backup = get_backup_flag()?; - - let address = get_address::()?; - let latest_height = api_client.latest_height()?; - - let (txs_in, ids) = get_new_transaction_messages::().await?; - - println!("Transactions In: {:?}", txs_in); - - if txs_in == vec![] { - let res = TxScanResponse { - txs: false, - block_height: latest_height, - }; - return Ok(res); - } - - let mut records_n_transitions_to_post = txs_in - .iter() - .zip(ids.iter()) - .map(|(tx, id)| { - let (encrypted_records, encrypted_transitions, invalid_tx) = - process_transaction(tx, address, *id)?; - Ok((encrypted_records, encrypted_transitions, invalid_tx)) - }) - .collect::, Vec, Option)>>>()?; - - if backup { - // separate records and transitions - let records_to_post = records_n_transitions_to_post - .iter_mut() - .flat_map(|(records, _, _)| records.clone()) - .collect::>(); - - let transitions_to_post = records_n_transitions_to_post - .iter_mut() - .flat_map(|(_, transitions, _)| transitions.clone()) - .collect::>(); - - let invalid_ids = records_n_transitions_to_post - .iter_mut() - .filter_map(|(_, _, invalid_id)| *invalid_id) - .collect::>(); - - let encrypted_record_ids = post_encrypted_data(records_to_post).await?; - let encrypted_transition_ids = post_encrypted_data(transitions_to_post).await?; - - encrypted_record_ids - .iter() - .map(|id| update_encrypted_data_synced_on_by_id(id)) - .collect::>>()?; - - encrypted_transition_ids - .iter() - .map(|id| update_encrypted_data_synced_on_by_id(id)) - .collect::>>()?; - - let ids_to_sync = ids - .iter() - .filter(|id| !invalid_ids.contains(id)) - .copied() - .collect::>(); - - synced(ids_to_sync).await?; - delete_invalid_transactions_in(invalid_ids).await?; - } else { - //NOTE - delete encrypted messages (The name may be misleading, but this is just to clear the encrypted transaction messages sent after they are received.) - delete_invalid_transactions_in(ids).await?; - } - - let res = TxScanResponse::new(true, latest_height); - Ok(res) - - // TODO - Check if the records were spent through another platform in the meantime by taking the min block height, getting all the tags and checking the records found against them. -} - -// NOTE - Production, passes window as parameter -///scans all blocks from last sync to cater for transitions, new records created -#[tauri::command(rename_all = "snake_case")] -pub async fn blocks_sync(height: u32, window: Window) -> AvailResult { - let network = get_network()?; - let last_sync = get_last_sync()?; - - print!("From Last Sync: {:?} to height: {:?}", last_sync, height); - - let task = tokio::spawn(async move { - let found_flag = match SupportedNetworks::from_str(network.as_str())? { - SupportedNetworks::Testnet3 => { - get_records::(last_sync, height, Some(window))? - } - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Invalid Network".to_string(), - "Invalid Network".to_string(), - )); - } - }; - - Ok(found_flag) - }); - - let result = task.await; - - let found_flag = match result { - Ok(res) => res?, - Err(_) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error scanning Aleo blockchain".to_string(), - "Error scanning Aleo blockchain".to_string(), - )); - } - }; - - print!("Scan Complete"); - - Ok(found_flag) -} - -// TODO - Handle splitting the payload if it maxes deserialization limit. -/// Backs up unsynced encrypted data to the server -#[tauri::command(rename_all = "snake_case")] -pub async fn sync_backup() -> AvailResult<()> { - let network = get_network()?; - let backup = get_backup_flag()?; - - if backup { - let last_backup_sync = get_last_backup_sync()?; - - /* Handle spent updates first */ - let encrypted_data_to_update = get_encrypted_data_to_update(last_backup_sync)?; - - let ids_to_update = encrypted_data_to_update - .iter() - .filter_map(|data| data.id) - .map(|id| id.to_string()) - .collect::>(); - - // post spent updates - match SupportedNetworks::from_str(network.as_str())? { - SupportedNetworks::Testnet3 => { - update_records_spent_backup::(ids_to_update).await? - } - _ => update_records_spent_backup::(ids_to_update).await?, - }; - - /* Handle posting new found encrypted data */ - let encrypted_data = get_encrypted_data_to_backup(last_backup_sync)?; - - println!("Encrypted Data: {:?}", encrypted_data); - - let ids = post_encrypted_data(encrypted_data).await?; - - ids.iter() - .map(|id| update_encrypted_data_synced_on_by_id(id)) - .collect::>>()?; - - let last_sync = get_last_sync()?; - - // get timestamp from block - let api_client = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => setup_client::(), - _ => setup_client::(), - }; - - let block = api_client?.get_block(last_sync)?; - let timestamp = get_timestamp_from_i64_utc(block.timestamp())?; - - update_last_backup_sync(timestamp) - } else { - Err(AvailError::new( - AvailErrorType::Internal, - "Backup not enabled, go to settings to enable it.".to_string(), - "Backup not enabled, go to settings to enable it.".to_string(), - )) - } -} - -pub async fn blocks_sync_test(height: u32) -> AvailResult { - let network = get_network()?; - let last_sync = get_last_sync()?; - - print!("From Last Sync: {:?} to height: {:?}", last_sync, height); - - let task = tokio::spawn(async move { - let found_flag = match SupportedNetworks::from_str(network.as_str())? { - SupportedNetworks::Testnet3 => get_records::(last_sync, height, None)?, - _ => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Invalid Network".to_string(), - "Invalid Network".to_string(), - )); - } - }; - - Ok(found_flag) - }); - - let result = task.await; - - let found_flag = match result { - Ok(res) => res?, - Err(_) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error scanning Aleo blockchain".to_string(), - "Error scanning Aleo blockchain".to_string(), - )); - } - }; - - print!("Scan Complete {}", found_flag); - - Ok(found_flag) -} - -#[cfg(test)] -mod test { - use super::*; - - use crate::api::encrypted_data::delete_all_server_storage; - use crate::api::user::delete_user; - use crate::models::{storage::languages::Languages, transfer::TransferRequest}; - use crate::services::account::generation::import_wallet; - use crate::{ - models::pointers::transaction::TransactionPointer, - services::{ - account::key_management::key_controller::KeyController, - authentication::session::get_session_after_creation, - local_storage::{ - encrypted_data::{ - drop_encrypted_data_table, get_encrypted_data_by_flavour, - initialize_encrypted_data_table, - }, - persistent_storage::{ - delete_user_preferences, initial_user_preferences, update_address, - update_last_sync, - }, - session::view::VIEWSESSION, - storage_api::transaction::decrypt_transactions_exec, - }, - record_handling::{records::find_aleo_credits_record_to_spend, transfer::transfer_raw}, - }, - }; - - use avail_common::{ - aleo_tools::program_manager::{ProgramManager, TransferType}, - models::constants::*, - }; - - #[cfg(target_os = "linux")] - use crate::services::account::key_management::key_controller::linuxKeyController; - #[cfg(target_os = "macos")] - use crate::services::account::key_management::key_controller::macKeyController; - #[cfg(target_os = "windows")] - use crate::services::account::key_management::key_controller::windowsKeyController; - - use snarkvm::prelude::{AleoID, Field, FromStr, PrivateKey, Testnet3, ToBytes, ViewKey}; - - fn test_setup_prerequisites() { - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let view_key = ViewKey::::try_from(&pk).unwrap(); - - drop_encrypted_data_table().unwrap(); - - delete_user_preferences().unwrap(); - // initialize the user preferences - initial_user_preferences( - false, - None, - None, - false, - false, - view_key.to_address().to_string(), - Languages::English, - ) - .unwrap(); - initialize_encrypted_data_table().unwrap(); - - VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); - } - #[tokio::test] - async fn test_blocks_scan() { - //NOTE - Don't forget to change OS depending on what you testing on -default should be linux - - /* -- Has to be called here cause has to await-- */ - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let ext = Identifier::::from_str("test").unwrap(); - - let key_controller = { - #[cfg(target_os = "linux")] - { - linuxKeyController {} - } - - #[cfg(target_os = "macos")] - { - macKeyController {} - } - - #[cfg(target_os = "windows")] - { - windowsKeyController {} - } - }; - - let vk = ViewKey::::try_from(&pk).unwrap(); - - delete_user_preferences().unwrap(); - initial_user_preferences( - false, - None, - None, - false, - true, - vk.to_address().to_string(), - Languages::English, - ) - .unwrap(); - - get_session_after_creation(&pk).await.unwrap(); - delete_user().await.unwrap(); - - key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - //delete_all_server_storage().await.unwrap(); - drop_encrypted_data_table().unwrap(); - - delete_user_preferences().unwrap(); - // initialize the user preferences - - import_wallet( - None, - STRONG_PASSWORD.to_string(), - false, - &pk.to_string(), - false, - Languages::English, - ) - .await - .unwrap(); - - let fee = 4000000u64; - let amount = 100000u64; - let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); - let asset_id = "credits".to_string(); - - let request = TransferRequest::new( - recipient_address.to_string(), - amount, - Some("Public to Private Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::Public, - false, - fee, - asset_id, - ); - - transfer_raw::(request, None).await.unwrap(); - - let recipient_view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY).unwrap(); - - VIEWSESSION - .set_view_session(&recipient_view_key.to_string()) - .unwrap(); - - update_address(&recipient_address.to_string()).unwrap(); - - tokio::time::sleep(tokio::time::Duration::from_secs(45)).await; - - let api_client = setup_client::().unwrap(); - - let latest_height = api_client.latest_height().unwrap(); - - blocks_sync_test(latest_height).await.unwrap(); - - //sync_backup().await.unwrap(); - } - - #[tokio::test] - async fn test_scan() { - test_setup_prerequisites(); - - let api_client = setup_client::().unwrap(); - - let latest_height = api_client.latest_height().unwrap(); - blocks_sync_test(latest_height).await.unwrap(); - } - - // this will fail when using the same program name with the same node instance or live network - #[tokio::test] - async fn test_deployment_scan() { - /* prepare record for fee */ - //NOTE - Don't forget to change OS depending on what you testing on -default should be linux - - /* -- Has to be called here cause has to await-- */ - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let ext = Identifier::::from_str("test").unwrap(); - - let key_controller = { - #[cfg(target_os = "linux")] - { - linuxKeyController {} - } - - #[cfg(target_os = "macos")] - { - macKeyController {} - } - - #[cfg(target_os = "windows")] - { - windowsKeyController {} - } - }; - - key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - delete_all_server_storage().await.unwrap(); - drop_encrypted_data_table().unwrap(); - - delete_user_preferences().unwrap(); - // initialize the user preferences - - import_wallet( - Some("Satoshi".to_string()), - STRONG_PASSWORD.to_string(), - false, - &pk.to_string(), - false, - Languages::English, - ) - .await - .unwrap(); - - let fee = 4000000u64; - let amount = 100000u64; - let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); - let asset_id = "credits".to_string(); - - let request = TransferRequest::new( - recipient_address.to_string(), - amount, - Some("Public to Private Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::PublicToPrivate, - false, - fee, - asset_id, - ); - - transfer_raw::(request, None).await.unwrap(); - - /* --Setup Done-- */ - - let recipient_view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY).unwrap(); - let vk_bytes = recipient_view_key.to_bytes_le().unwrap(); - - VIEWSESSION - .set_view_session(&recipient_view_key.to_string()) - .unwrap(); - - let _res = txs_sync().await.unwrap(); - - let (string, program) = Program::::parse( - r" -program ftesting.aleo; - -mapping store: -key as u32.public; -value as u32.public; - -function compute: -input r0 as u32.private; -add r0 r0 into r1; -output r1 as u32.public;", - ) - .unwrap(); - assert!( - string.is_empty(), - "Parser did not consume all of the string: '{string}'" - ); - - let pk2 = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); - - let api_client = setup_client::().unwrap(); - - let mut program_manager = - ProgramManager::::new(Some(pk2), None, Some(api_client.clone()), None) - .unwrap(); - - program_manager.add_program(&program).unwrap(); - - let (fee_record, _fee_commitment, _fee_id) = - find_aleo_credits_record_to_spend::(&(amount - 1000), vec![]).unwrap(); - - let _deployment = program_manager - .deploy_program(program.id(), 0u64, Some(fee_record), None) - .unwrap(); - - let latest_height1 = api_client.latest_height().unwrap(); - update_last_sync(latest_height1).unwrap(); - - // go to sleep for 2 minutes - tokio::time::sleep(tokio::time::Duration::from_secs(25)).await; - - let latest_height2 = api_client.latest_height().unwrap(); - blocks_sync_test(latest_height2).await.unwrap(); - } - - #[tokio::test] - async fn test_txs_scan() { - /* prepare record for fee */ - /* -- Has to be called here cause has to await-- */ - let pk = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); - let ext = Identifier::::from_str("test").unwrap(); - - let key_controller = { - #[cfg(target_os = "linux")] - { - linuxKeyController {} - } - - #[cfg(target_os = "macos")] - { - macKeyController {} - } - - #[cfg(target_os = "windows")] - { - windowsKeyController {} - } - }; - - match key_controller.delete_key(Some(STRONG_PASSWORD), ext) { - Ok(_) => println!("Key deleted"), - Err(e) => println!("Error deleting key: {:?}", e), - } - - drop_encrypted_data_table().unwrap(); - - delete_user_preferences().unwrap(); - // initialize the user preferences - - import_wallet( - Some("SatoshiXY".to_string()), - STRONG_PASSWORD.to_string(), - false, - &pk.to_string(), - false, - Languages::English, - ) - .await - .unwrap(); - - println!("Imported Successfully"); - - let fee = 300000u64; - let amount = 400000u64; - let recipient_address = Address::::from_str(TESTNET3_ADDRESS_2).unwrap(); - let asset_id = "credits".to_string(); - - let request = TransferRequest::new( - recipient_address.to_string(), - amount, - Some("Public to Private Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::PublicToPrivate, - false, - fee, - asset_id, - ); - - transfer_raw::(request, None).await.unwrap(); - - /* --Setup Done-- */ - - println!("Testing Complete transaction storage"); - let data = get_encrypted_data_by_flavour( - avail_common::models::encrypted_data::EncryptedDataTypeCommon::TransactionMessage, - ) - .unwrap(); - println!("{:?}\n", data); - let transactions = decrypt_transactions_exec::(data.clone()).unwrap(); - println!("{:?}\n", transactions); - - for data_p in data { - let event = TransactionPointer::::decrypt_to_event(data_p).unwrap(); - println!("{:?}", event); - } - - let recipient_view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY2).unwrap(); - let vk_bytes = recipient_view_key.to_bytes_le().unwrap(); - - VIEWSESSION - .set_view_session(&recipient_view_key.to_string()) - .unwrap(); - update_address(&recipient_address.to_string()).unwrap(); - - let _res = txs_sync().await.unwrap(); - - println!("res: {:?}", _res); - } - - #[test] - fn test_process_transaction_failed_verification() { - let tx_id = &AleoID::, 29793>::from_str( - "at1w8t8pkc9xuf2p05gp9fanxpx0h53jmpguc07ja34s3jm905v65gss306rr", - ) - .unwrap(); - - let transition_id = &AleoID::, 30049>::from_str( - "au1w8t8pkc9xuf2p05gp9fanxpx0h53jmpguc07ja34s3jm905v65gss306rr", - ) - .unwrap(); - - let test_transaction_message = TransactionMessage::::new( - tx_id.clone(), - 0u32, - "Zack".to_string(), - Some("Hello".to_string()), - ); - - let address = Address::::from_str(TESTNET_ADDRESS).unwrap(); - - let res = process_transaction(&test_transaction_message, address, Uuid::new_v4()).unwrap(); - - println!("res: {:?}", res); - } - - #[test] - fn test_get_latest_height() { - let api_client = setup_client::().unwrap(); - - let latest_height = api_client.latest_height().unwrap(); - println!("latest_height: {:?}", latest_height); - } - - #[tokio::test] - async fn test_transition_ownership() { - /* prepare record for fee */ - //NOTE - Don't forget to change OS depending on what you testing on -default should be linux - - /* -- Has to be called here cause has to await-- */ - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let ext = Identifier::::from_str("test").unwrap(); - - let key_controller = { - #[cfg(target_os = "linux")] - { - linuxKeyController {} - } - - #[cfg(target_os = "macos")] - { - macKeyController {} - } - - #[cfg(target_os = "windows")] - { - windowsKeyController {} - } - }; - - key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - drop_encrypted_data_table().unwrap(); - - delete_user_preferences().unwrap(); - // initialize the user preferences - - import_wallet( - Some("SatoshiX".to_string()), - STRONG_PASSWORD.to_string(), - false, - &pk.to_string(), - false, - Languages::English, - ) - .await - .unwrap(); - - let fee = 4000000u64; - let amount = 100000u64; - let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); - let asset_id = "credits".to_string(); - - let request = TransferRequest::new( - recipient_address.to_string(), - amount, - Some("Public to Private Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::PublicToPrivate, - false, - fee, - asset_id, - ); - - transfer_raw::(request, None).await.unwrap(); - - /* --Setup Done-- */ - - let recipient_view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY).unwrap(); - let vk_bytes = recipient_view_key.to_bytes_le().unwrap(); - - VIEWSESSION - .set_view_session(&recipient_view_key.to_string()) - .unwrap(); - - tokio::time::sleep(tokio::time::Duration::from_secs(30)).await; - - let api_client = setup_client::().unwrap(); - let latest_height2 = api_client.latest_height().unwrap(); - blocks_sync_test(latest_height2).await.unwrap(); - } -} diff --git a/backend/src/services/record_handling/transfer.rs b/backend/src/services/record_handling/transfer.rs deleted file mode 100644 index 01fd4c91..00000000 --- a/backend/src/services/record_handling/transfer.rs +++ /dev/null @@ -1,1413 +0,0 @@ -use chrono::{DateTime, Local}; - -use dirs; -use snarkvm::{ledger::transactions::ConfirmedTransaction, prelude::*}; -use tauri::{Manager, Window}; -use tauri_plugin_http::reqwest; - -use std::fs; -use std::{ops::Add, str::FromStr}; -use tokio::time::{Duration, Instant}; - -use crate::api::aleo_client::setup_client; -use crate::services::local_storage::encrypted_data::update_encrypted_transaction_state_by_id; -use crate::{ - helpers::utils::get_timestamp_from_i64, - services::authentication::session::get_session_after_creation, - services::local_storage::storage_api::records::update_record_spent_local, -}; - -use crate::models::{pointers::transaction::TransactionPointer, transfer::TransferRequest}; - -use avail_common::{ - aleo_tools::program_manager::{ProgramManager, TransferType}, - errors::{AvailError, AvailErrorType, AvailResult}, - models::{ - encrypted_data::{EventTypeCommon, TransactionState}, - network::SupportedNetworks, - }, -}; - -use crate::services::local_storage::{ - persistent_storage::{get_address, get_network}, - session::password::PASS, - utils::get_private_key, -}; - -use super::records::*; -use super::utils::{get_address_from_recipient, handle_encrypted_storage_and_message}; - -/// Generic ARC20 token transfer function -#[tauri::command(rename_all = "snake_case")] -pub async fn transfer(request: TransferRequest, window: Window) -> AvailResult { - let network = get_network()?; - - let transfer_task_res = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - tokio::task::spawn_blocking(move || transfer_raw::(request, Some(window))) - .await? - } - _ => { - tokio::task::spawn_blocking(move || transfer_raw::(request, Some(window))) - .await? - } - } - .await?; - - PASS.extend_session()?; - - Ok(format!("Transaction '{}' Successful", transfer_task_res)) -} - -pub async fn transfer_raw( - request: TransferRequest, - window: Option, -) -> AvailResult { - match request.transfer_type() { - TransferType::Private => { - transfer_private_util::( - request.asset_id().as_str(), - request.amount(), - request.fee(), - request.fee_private(), - request.message().clone(), - request.recipient().as_str(), - request.password().clone(), - window, - ) - .await - } - TransferType::PublicToPrivate => { - transfer_public_to_private_util::( - request.asset_id().as_str(), - request.amount(), - request.fee(), - request.fee_private(), - request.message().clone(), - request.recipient().as_str(), - request.password().clone(), - window, - ) - .await - } - TransferType::PrivateToPublic => { - transfer_private_to_public_util::( - request.asset_id().as_str(), - request.amount(), - request.fee(), - request.fee_private(), - request.message().clone(), - request.recipient().as_str(), - request.password().clone(), - window, - ) - .await - } - TransferType::Public => { - transfer_public::( - request.asset_id().as_str(), - request.amount(), - request.fee(), - request.fee_private(), - request.message().clone(), - request.recipient().as_str(), - request.password().clone(), - window, - ) - .await - } - } -} - -/// Transfer tokens privately -async fn transfer_private_util( - asset_id: &str, - amount: &u64, - fee: &u64, - fee_private: &bool, - message: Option, - to: &str, - password: Option, - window: Option, -) -> AvailResult { - let api_client = setup_client::()?; - - let sender_address = get_address::()?; - - let private_key = get_private_key::(password)?; - - //extend session auth - let _session_task = get_session_after_creation::(&private_key).await?; - - let recipient = get_address_from_recipient::(to).await?; - let mut record_nonces: Vec = vec![]; - - let program_manager = - ProgramManager::::new(Some(private_key), None, Some(api_client.clone()), None).unwrap(); - - // get required records if private tx - let (token_record, _token_commitment, token_id) = - find_tokens_to_spend::(asset_id, amount, vec![])?; - let token_nonce = token_record.nonce().to_string(); - record_nonces.push(token_nonce); - - let (fee_record, _fee_commitment, fee_id) = match fee_private { - true => { - let (fee_record, _fee_commitment, fee_id) = - find_aleo_credits_record_to_spend::(fee, vec![])?; - let fee_nonce = fee_record.nonce().to_string(); - record_nonces.push(fee_nonce); - (Some(fee_record), Some(_fee_commitment), Some(fee_id)) - } - false => (None, None, None), - }; - - let program_id = format!("{}.aleo", asset_id); - - let mut pending_transaction = TransactionPointer::::new( - Some(to.to_string()), - None, - TransactionState::Processing, - None, - Some(program_id.clone()), - Some("transfer_private".to_string()), - vec![], - record_nonces, - Local::now(), - None, - message, - EventTypeCommon::Send, - Some(*amount as f64 / 1000000.0), - Some(*fee as f64 / 1000000.0), - None, - ); - - let pending_tx_id = pending_transaction.encrypt_and_store(sender_address)?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_tx_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - let amount = amount.to_owned(); - let fee = fee.to_owned(); - - // update spent states - update_record_spent_local::(&token_id, true)?; - if let Some(fee_id) = fee_id.clone() { - update_record_spent_local::(&fee_id, true)?; - } - - let transaction_id = match program_manager.transfer( - amount, - fee, - recipient, - TransferType::Private, - None, - Some(token_record), - fee_record.clone(), - &program_id, - ) { - Ok(tx_id) => tx_id, - Err(e) => { - println!("{:?}", e); - update_record_spent_local::(&token_id, false)?; - - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, false)?; - } - - pending_transaction.update_failed_transaction( - "Transaction execution failed, no records were spent.".to_string(), - ); - - let encrypted_failed_transaction = - pending_transaction.to_encrypted_data(sender_address)?; - - update_encrypted_transaction_state_by_id( - &pending_tx_id, - &encrypted_failed_transaction.ciphertext, - &encrypted_failed_transaction.nonce, - TransactionState::Failed, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_tx_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - return Err(AvailError::new( - AvailErrorType::Internal, - "Error transferring tokens".to_string(), - format!("Error transferring tokens: {:?}", e), - )); - } - }; - - let encrypted_message_task = tokio::spawn(async move { - handle_encrypted_storage_and_message( - transaction_id, - recipient, - &pending_tx_id, - Some(token_id), - fee_id, - false, - window, - ) - .await - }); - - match encrypted_message_task.await? { - Ok(_) => {} - Err(e) => return Err(e), - }; - - Ok(format!("Transaction Id {}", transaction_id)) -} - -/// Convert public tokens to private tokens -async fn transfer_public_to_private_util( - asset_id: &str, - amount: &u64, - fee: &u64, - fee_private: &bool, - message: Option, - to: &str, - password: Option, - window: Option, -) -> AvailResult { - let api_client = setup_client::()?; - let sender_address = get_address::()?; - let private_key = get_private_key::(password)?; - - //extend session auth - let _session_task = get_session_after_creation::(&private_key).await?; - let recipient = get_address_from_recipient::(to).await?; - let mut record_nonces: Vec = vec![]; - - let program_manager = - ProgramManager::::new(Some(private_key), None, Some(api_client.clone()), None)?; - - let program_id = format!("{}.aleo", asset_id); - - //get required records if private fee - let (fee_record, _fee_commitment, fee_id) = match fee_private { - true => { - let (fee_record, _fee_commitment, fee_id) = - find_aleo_credits_record_to_spend::(fee, vec![])?; - - let fee_nonce = fee_record.nonce().to_string(); - record_nonces.push(fee_nonce); - - update_record_spent_local::(&fee_id, true)?; - (Some(fee_record), Some(_fee_commitment), Some(fee_id)) - } - false => (None, None, None), - }; - - let mut pending_transaction = TransactionPointer::::new( - Some(to.to_string()), - None, - TransactionState::Processing, - None, - Some(program_id.clone()), - Some("transfer_public_to_private".to_string()), - vec![], - record_nonces, - Local::now(), - None, - message, - EventTypeCommon::Send, - Some(*amount as f64 / 1000000.0), - Some(*fee as f64 / 1000000.0), - None, - ); - - let pending_tx_id = pending_transaction.encrypt_and_store(sender_address)?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_tx_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - } - }; - - // update spent states - if let Some(fee_id) = fee_id.clone() { - update_record_spent_local::(&fee_id, true)?; - } - - let transaction_id = match program_manager.transfer( - amount.to_owned(), - fee.to_owned(), - recipient, - TransferType::PublicToPrivate, - None, - None, - fee_record.clone(), - &program_id, - ) { - Ok(tx_id) => tx_id, - Err(e) => { - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, false)?; - } - - pending_transaction.update_failed_transaction( - "Transaction execution failed, no records were spent.".to_string(), - ); - - let encrypted_failed_transaction = - pending_transaction.to_encrypted_data(sender_address)?; - - update_encrypted_transaction_state_by_id( - &pending_tx_id, - &encrypted_failed_transaction.ciphertext, - &encrypted_failed_transaction.nonce, - TransactionState::Failed, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_tx_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - return Err(AvailError::new( - AvailErrorType::Internal, - "Error transferring tokens".to_string(), - format!("Error transferring tokens: {:?}", e), - )); - } - }; - - handle_encrypted_storage_and_message( - transaction_id, - recipient, - &pending_tx_id, - None, - fee_id, - false, - window, - ) - .await?; - - Ok(format!("Transaction Id {}", transaction_id.to_string())) -} - -/// Convert private tokens to public tokens -async fn transfer_private_to_public_util( - asset_id: &str, - amount: &u64, - fee: &u64, - fee_private: &bool, - message: Option, - to: &str, - password: Option, - window: Option, -) -> AvailResult { - let api_client = setup_client::()?; - let sender_address = get_address::()?; - let private_key = get_private_key::(password)?; - - //extend session auth - let _session_task = get_session_after_creation::(&private_key).await?; - let recipient = get_address_from_recipient::(to).await?; - let mut record_nonces: Vec = vec![]; - - let program_manager = - ProgramManager::::new(Some(private_key), None, Some(api_client.clone()), None).unwrap(); - - // get required records if private tx - let (token_record, _token_commitment, token_id) = - find_tokens_to_spend::(asset_id, amount, vec![])?; - let token_nonce = token_record.nonce().to_string(); - record_nonces.push(token_nonce); - - let (fee_record, _fee_commitment, fee_id) = match fee_private { - true => { - let (fee_record, _fee_commitment, fee_id) = - find_aleo_credits_record_to_spend::(fee, vec![])?; - - let fee_nonce = fee_record.nonce().to_string(); - record_nonces.push(fee_nonce); - - update_record_spent_local::(&fee_id, true)?; - (Some(fee_record), Some(_fee_commitment), Some(fee_id)) - } - false => (None, None, None), - }; - - let program_id = format!("{}.aleo", asset_id); - - let mut pending_transaction = TransactionPointer::::new( - Some(to.to_string()), - None, - TransactionState::Processing, - None, - Some(program_id.clone()), - Some("transfer_private_to_public".to_string()), - vec![], - record_nonces, - Local::now(), - None, - message, - EventTypeCommon::Send, - Some(*amount as f64 / 1000000.0), - Some(*fee as f64 / 1000000.0), - None, - ); - - let pending_tx_id = pending_transaction.encrypt_and_store(sender_address)?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_tx_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - // update spent states - update_record_spent_local::(&token_id, true)?; - if let Some(fee_id) = fee_id.clone() { - update_record_spent_local::(&fee_id, true)?; - } - - let transfer_res = match program_manager.transfer( - amount.to_owned(), - fee.to_owned(), - recipient, - TransferType::PrivateToPublic, - None, - Some(token_record.clone()), - fee_record.clone(), - &program_id, - ) { - Ok(tx_id) => tx_id, - Err(e) => { - update_record_spent_local::(&token_id, false)?; - - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, false)?; - } - - pending_transaction.update_failed_transaction( - "Transaction execution failed, no records were spent.".to_string(), - ); - - let encrypted_failed_transaction = - pending_transaction.to_encrypted_data(sender_address)?; - - update_encrypted_transaction_state_by_id( - &pending_tx_id, - &encrypted_failed_transaction.ciphertext, - &encrypted_failed_transaction.nonce, - TransactionState::Failed, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_tx_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - return Err(AvailError::new( - AvailErrorType::Internal, - "Error transferring tokens".to_string(), - format!("Error transferring tokens: {:?}", e), - )); - } - }; - - handle_encrypted_storage_and_message( - transfer_res, - recipient, - &pending_tx_id, - Some(token_id), - fee_id, - false, - window, - ) - .await?; - - Ok(format!("Transaction Id {}", transfer_res)) -} - -// Transfer tokens publicly -async fn transfer_public( - asset_id: &str, - amount: &u64, - fee: &u64, - fee_private: &bool, - message: Option, - to: &str, - password: Option, - window: Option, -) -> AvailResult { - let api_client = setup_client::()?; - let sender_address = get_address::()?; - let private_key = get_private_key::(password)?; - - //extend session auth - get_session_after_creation::(&private_key).await?; - let recipient = get_address_from_recipient::(to).await?; - - let program_manager = - ProgramManager::::new(Some(private_key), None, Some(api_client.clone()), None)?; - - let mut record_nonces: Vec = vec![]; - - // get required records if private fee - let (fee_record, _fee_commitment, fee_id) = match fee_private { - true => { - let (fee_record, _fee_commitment, fee_id) = - find_aleo_credits_record_to_spend::(fee, vec![])?; - - let fee_nonce = fee_record.nonce().to_string(); - record_nonces.push(fee_nonce); - - update_record_spent_local::(&fee_id, true)?; - (Some(fee_record), Some(_fee_commitment), Some(fee_id)) - } - false => (None, None, None), - }; - - let program_id = format!("{}.aleo", asset_id); - - let mut pending_transaction = TransactionPointer::::new( - Some(to.to_string()), - None, - TransactionState::Processing, - None, - Some(program_id.clone()), - Some("transfer_public".to_string()), - vec![], - record_nonces, - Local::now(), - None, - message, - EventTypeCommon::Send, - Some(*amount as f64 / 1000000.0), - Some(*fee as f64 / 1000000.0), - None, - ); - - let pending_tx_id = pending_transaction.encrypt_and_store(sender_address)?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_tx_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - // update spent states - if let Some(fee_id) = fee_id.clone() { - update_record_spent_local::(&fee_id, true)?; - } - - let transfer_res = match program_manager.transfer( - amount.to_owned(), - fee.to_owned(), - recipient, - TransferType::Public, - None, - None, - fee_record.clone(), - &program_id, - ) { - Ok(tx_id) => tx_id, - Err(e) => { - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, false)?; - } - - pending_transaction.update_failed_transaction( - "Transaction execution failed, no records were spent.".to_string(), - ); - - let encrypted_failed_transaction = - pending_transaction.to_encrypted_data(sender_address)?; - - update_encrypted_transaction_state_by_id( - &pending_tx_id, - &encrypted_failed_transaction.ciphertext, - &encrypted_failed_transaction.nonce, - TransactionState::Failed, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_tx_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - return Err(AvailError::new( - AvailErrorType::Internal, - "Error transferring tokens".to_string(), - format!("Error transferring tokens: {:?}", e), - )); - } - }; - - handle_encrypted_storage_and_message( - transfer_res, - recipient, - &pending_tx_id, - None, - fee_id, - false, - window, - ) - .await?; - - Ok(format!("Transaction Id {}", transfer_res)) -} - -// TODO - Add timer threshold for when to stop searching for transaction, and keep in unconfirmed state -/// Find Transaction on chain and handle state -pub fn find_confirmed_block_height( - tx_id: N::TransactionID, -) -> AvailResult<( - u32, - Vec>, - DateTime, - TransactionState, - Option, - Option>, - Option, -)> { - let api_client = setup_client::()?; - - let latest_block_height = api_client.latest_height()?; - - let mut flag: bool = false; - let mut iter = latest_block_height; - - let start_time = Instant::now(); - let search_duration = Duration::from_secs(180); - - println!("Waiting for transaction to confirm in block on chain"); - while !flag && start_time.elapsed() < search_duration { - println!("Checking block {}", iter); - let latest_height = api_client.latest_height()?; - - if iter > latest_height { - println!("Iter > Latest Height"); - std::thread::sleep(std::time::Duration::from_secs(3)); - continue; - } - - let block = match api_client.get_block(iter) { - Ok(block) => { - println!("Block {} found", iter); - block - } - Err(e) => { - println!("Error getting block: {:?}\n", e); - std::thread::sleep(std::time::Duration::from_secs(3)); - continue; - } - }; - - let transactions = block.transactions(); - - // transactions that where in excess of the max limit of the block - let aborted_transactions = block.aborted_transaction_ids(); - - if aborted_transactions.contains(&tx_id) { - flag = true; - let timestamp = get_timestamp_from_i64(block.timestamp())?; - return Ok(( - iter, - vec![], - timestamp, - TransactionState::Aborted, - None, - None, - None, - )); - } - - let tx = transactions.get(&tx_id); - - // TODO - Make it default to unconfirmed after 1 minute 30 seconds - println!("In Progress"); - if let Some(tx) = tx { - println!("Transaction found"); - // deduce state - - if let ConfirmedTransaction::::AcceptedDeploy(_, _, _) = tx { - flag = true; - let timestamp = get_timestamp_from_i64(block.timestamp())?; - let fee = tx.transaction().fee_amount()?; - let mut transitions: Vec> = vec![]; - - if let Some(fee_transition) = tx.transaction().fee_transition() { - let transition = fee_transition.transition(); - transitions.push(transition.clone()); - } - - return Ok(( - iter, - transitions, - timestamp, - TransactionState::Aborted, - None, - None, - Some(*fee as f64 / 1000000.0), - )); - } else if let ConfirmedTransaction::::AcceptedExecute(_, _, _) = tx { - flag = true; - println!("C1"); - let timestamp = get_timestamp_from_i64(block.timestamp())?; - println!("C2"); - let fee = tx.transaction().fee_amount()?; - println!("C3"); - - let transitions = tx.transitions().cloned().collect::>(); - println!("C4"); - return Ok(( - iter, - transitions, - timestamp, - TransactionState::Confirmed, - None, - None, - Some(*fee as f64 / 1000000.0), - )); - } - } else { - for tx in transactions.iter() { - if let ConfirmedTransaction::::RejectedDeploy(_, fee_tx, _, _) = tx { - if tx.to_unconfirmed_transaction_id()? == tx_id { - flag = true; - let timestamp = get_timestamp_from_i64(block.timestamp())?; - let fee = tx.transaction().fee_amount()?; - - let mut transitions: Vec> = vec![]; - - if let Some(fee_transition) = tx.transaction().fee_transition() { - let transition = fee_transition.transition(); - transitions.push(transition.clone()); - } - - return Ok(( - iter, - transitions, - timestamp, - TransactionState::Rejected, - Some(fee_tx.id()), - None, - Some(*fee as f64 / 1000000.0), - )); - } - } else if let ConfirmedTransaction::::RejectedExecute( - _, - fee_tx, - rejected_execution, - _, - ) = tx - { - if tx.to_unconfirmed_transaction_id()? == tx_id { - flag = true; - let timestamp = get_timestamp_from_i64(block.timestamp())?; - let fee = tx.transaction().fee_amount()?; - let transitions = tx.transitions().cloned().collect::>(); - if let Some(rejected_execution) = rejected_execution.execution() { - return Ok(( - iter, - transitions, - timestamp, - TransactionState::Rejected, - Some(fee_tx.id()), - Some(rejected_execution.to_owned()), - Some(*fee as f64 / 1000000.0), - )); - } - - return Ok(( - iter, - transitions, - timestamp, - TransactionState::Rejected, - Some(fee_tx.id()), - None, - Some(*fee as f64 / 1000000.0), - )); - } - } - } - } - - iter = iter.add(1); - std::thread::sleep(std::time::Duration::from_secs(7)); - } - - Err(AvailError::new( - AvailErrorType::NotFound, - "Transaction is unconfirmed, this might be due to issues with the Aleo network." - .to_string(), - "Transaction is unconfirmed, this might be due to issues with the Aleo network." - .to_string(), - )) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pre_install_inclusion_prover() -> AvailResult<()> { - let path = match dirs::home_dir() { - Some(home_dir) => home_dir - .join(".aleo") - .join("resources") - .join("inclusion.prover.cd85cc5"), - - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error getting home directory".to_string(), - "Error getting home directory".to_string(), - )) - } - }; - - if path.as_path().exists() { - println!("inclusion.prover.cd85cc5 already exists"); - Ok(()) - } else { - let client = reqwest::Client::new(); - - println!("Downloading inclusion.prover.cd85cc5..."); - - let task = tokio::spawn(async move { - client - .get("https://s3-us-west-1.amazonaws.com/aleo-resources/inclusion.prover.cd85cc5") - .send() - .await - }); - - let res = match task.await? { - Ok(res) => res, - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error downloading inclusion.prover.cd85cc5".to_string(), - format!("Error downloading inclusion.prover.cd85cc5: {:?}", e), - )) - } - }; - - println!("Finished downloading inclusion.prover.cd85cc5..."); - - let body = res.bytes().await?; - - fs::write(path, body)?; - - println!("Finished writing inclusion.prover.cd85cc5..."); - - Ok(()) - } -} - -#[cfg(test)] -mod transfer_tests { - - use crate::models::{ - storage::languages::Languages, - wallet_connect::{get_event::GetEventsRequest, records::GetRecordsRequest}, - }; - - use crate::services::account::generation::import_wallet; - use crate::services::account::key_management::key_controller::KeyController; - use crate::services::local_storage::session::view::VIEWSESSION; - use crate::services::local_storage::{ - encrypted_data::drop_encrypted_data_table, - persistent_storage::{delete_user_preferences, update_address}, - storage_api::{event::get_avail_events_raw, records::get_record_pointers}, - }; - use crate::services::record_handling::sync::txs_sync; - use avail_common::models::constants::*; - - use snarkvm::prelude::{Identifier, Testnet3}; - - #[cfg(target_os = "linux")] - use crate::services::account::key_management::key_controller::linuxKeyController; - - #[cfg(target_os = "macos")] - use crate::services::account::key_management::key_controller::macKeyController; - - #[cfg(target_os = "windows")] - use crate::services::account::key_management::key_controller::windowsKeyController; - - use super::*; - async fn test_setup_prerequisites() { - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let ext = Identifier::::from_str("test").unwrap(); - - #[cfg(target_os = "macos")] - let mac_key_controller = macKeyController {}; - #[cfg(target_os = "macos")] - mac_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - #[cfg(target_os = "linux")] - let linux_key_controller = linuxKeyController {}; - #[cfg(target_os = "linux")] - linux_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - #[cfg(target_os = "windows")] - let windows_key_controller = windowsKeyController {}; - #[cfg(target_os = "windows")] - windows_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - drop_encrypted_data_table().unwrap(); - delete_user_preferences().unwrap(); - // initialize the user preferences - - import_wallet( - Some("Satoshi".to_string()), - STRONG_PASSWORD.to_string(), - false, - &pk.to_string(), - false, - Languages::English, - ) - .await - .unwrap(); - } - - #[tokio::test] - async fn test_private_transfer() { - //NOTE - Don't forget to change OS depending on what you testing on -default should be linux - - /* -- Has to be called here cause has to await-- */ - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let ext = Identifier::::from_str("test").unwrap(); - - #[cfg(target_os = "macos")] - let mac_key_controller = macKeyController {}; - #[cfg(target_os = "macos")] - mac_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - #[cfg(target_os = "linux")] - let linux_key_controller = linuxKeyController {}; - #[cfg(target_os = "linux")] - linux_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - #[cfg(target_os = "windows")] - let windows_key_controller = windowsKeyController {}; - #[cfg(target_os = "windows")] - windows_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - drop_encrypted_data_table().unwrap(); - delete_user_preferences().unwrap(); - // initialize the user preferences - - import_wallet( - Some("Satoshi".to_string()), - STRONG_PASSWORD.to_string(), - false, - &pk.to_string(), - false, - Languages::English, - ) - .await - .unwrap(); - - let fee = 300000u64; - let amount = 900000u64; - let recipient_address = Address::::from_str(TESTNET_ADDRESS).unwrap(); - let asset_id = "credits".to_string(); - - let request = TransferRequest::new( - recipient_address.to_string(), - amount, - Some("Private Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::Private, - false, - fee, - asset_id, - ); - - transfer_raw::(request, None).await.unwrap(); - - /* --SETUP COMPLETE */ - - let get_records_request = GetRecordsRequest::new(None, None, None); - let (records, ids) = get_record_pointers::(get_records_request.clone()).unwrap(); - - println!("Initial Records: {:?}\n", records); - - let get_events_request = GetEventsRequest { - filter: None, - page: None, - }; - let events = get_avail_events_raw::(get_events_request.clone()).unwrap(); - - println!("Initial Events: {:?}\n", events); - - // call fee estimation - let fee = 300000u64; - let amount = 900000u64; - let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); - let asset_id = "credits".to_string(); - - let request = TransferRequest::new( - recipient_address.to_string(), - amount, - Some("Private Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::Private, - false, - fee, - asset_id, - ); - - transfer_raw::(request, None).await.unwrap(); - - // get events and display - let (records, _ids) = get_record_pointers::(get_records_request.clone()).unwrap(); - - println!("Post Private Transfer Sender Records: {:?}\n", records); - - let events = get_avail_events_raw::(get_events_request.clone()).unwrap(); - - println!("Post Private Transfer Sender Events: {:?}\n", events); - - let recipient_view_key = ViewKey::::from_str(TESTNET3_VIEW_KEY).unwrap(); - let vk_bytes = recipient_view_key.to_bytes_le().unwrap(); - - VIEWSESSION - .set_view_session(&recipient_view_key.to_string()) - .unwrap(); - - update_address(&recipient_address.to_string()).unwrap(); - - let _res = txs_sync().await.unwrap(); - - let (records, ids) = get_record_pointers::(get_records_request).unwrap(); - - println!("Post Private Transfer Receiver Records: {:?}\n", records); - - let events = get_avail_events_raw::(get_events_request).unwrap(); - - println!("Post Private Transfer Receiver Events: {:?}\n", events); - } - - #[tokio::test] - async fn test_transfer_public_to_private() { - //NOTE - Don't forget to change OS depending on what you testing on -default should be linux - - /* -- Has to be called here cause has to await-- */ - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let ext = Identifier::::from_str("test").unwrap(); - - #[cfg(target_os = "macos")] - let mac_key_controller = macKeyController {}; - #[cfg(target_os = "macos")] - mac_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - #[cfg(target_os = "linux")] - let linux_key_controller = linuxKeyController {}; - #[cfg(target_os = "linux")] - linux_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - #[cfg(target_os = "windows")] - let windows_key_controller = windowsKeyController {}; - #[cfg(target_os = "windows")] - windows_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - drop_encrypted_data_table().unwrap(); - delete_user_preferences().unwrap(); - // initialize the user preferences - - import_wallet( - Some("Satoshi".to_string()), - STRONG_PASSWORD.to_string(), - false, - &pk.to_string(), - false, - Languages::English, - ) - .await - .unwrap(); - - let fee = 300000u64; - let amount = 900000u64; - let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); - let asset_id = "credits".to_string(); - - let request = TransferRequest::new( - recipient_address.to_string(), - amount, - Some("Public to Private Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::PublicToPrivate, - false, - fee, - asset_id, - ); - - transfer_raw::(request, None).await.unwrap(); - } - - #[tokio::test] - async fn test_transfer_private_to_public() { - //NOTE - Don't forget to change OS depending on what you testing on -default should be linux - - /* -- Has to be called here cause has to await-- */ - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let ext = Identifier::::from_str("test").unwrap(); - - #[cfg(target_os = "macos")] - let mac_key_controller = macKeyController {}; - #[cfg(target_os = "macos")] - mac_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - #[cfg(target_os = "linux")] - let linux_key_controller = linuxKeyController {}; - #[cfg(target_os = "linux")] - linux_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - #[cfg(target_os = "windows")] - let windows_key_controller = windowsKeyController {}; - #[cfg(target_os = "windows")] - windows_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - drop_encrypted_data_table().unwrap(); - delete_user_preferences().unwrap(); - // initialize the user preferences - - import_wallet( - Some("Satoshi".to_string()), - STRONG_PASSWORD.to_string(), - false, - &pk.to_string(), - false, - Languages::English, - ) - .await - .unwrap(); - - let fee = 300000u64; - let amount = 900000u64; - let recipient_address = Address::::from_str(TESTNET_ADDRESS).unwrap(); - let asset_id = "credits".to_string(); - - let request = TransferRequest::new( - recipient_address.to_string(), - amount, - Some("Public to Private Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::PublicToPrivate, - false, - fee, - asset_id, - ); - - transfer_raw::(request, None).await.unwrap(); - - /* --SETUP COMPLETE */ - - let fee = 4000000u64; - let amount = 100000u64; - let recipient_address = Address::::from_str(TESTNET3_ADDRESS).unwrap(); - let asset_id = "credits".to_string(); - - let request = TransferRequest::new( - recipient_address.to_string(), - amount, - Some("Private to Public Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::PrivateToPublic, - false, - fee, - asset_id, - ); - - transfer_raw::(request, None).await.unwrap(); - } - - #[tokio::test] - async fn test_transfer_public() { - //NOTE - Don't forget to change OS depending on what you testing on -default should be linux - - /* -- Has to be called here cause has to await-- */ - - let pk = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); - let ext = Identifier::::from_str("test").unwrap(); - - #[cfg(target_os = "macos")] - let mac_key_controller = macKeyController {}; - #[cfg(target_os = "macos")] - mac_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - #[cfg(target_os = "linux")] - let linux_key_controller = linuxKeyController {}; - #[cfg(target_os = "linux")] - linux_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - #[cfg(target_os = "windows")] - let windows_key_controller = windowsKeyController {}; - #[cfg(target_os = "windows")] - windows_key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - drop_encrypted_data_table().unwrap(); - delete_user_preferences().unwrap(); - // initialize the user preferences - - import_wallet( - Some("Satoshi".to_string()), - STRONG_PASSWORD.to_string(), - false, - &pk.to_string(), - false, - Languages::English, - ) - .await - .unwrap(); - /* --SETUP COMPLETE */ - - let fee = 4000000u64; - let amount = 100000u64; - let recipient_address = Address::::from_str("").unwrap(); - let asset_id = "credits".to_string(); - - let request = TransferRequest::new( - recipient_address.to_string(), - amount, - Some("Public Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::Public, - false, - fee, - asset_id, - ); - - transfer_raw::(request, None).await.unwrap(); - } - - // Transfer funds to test wallet on local dev network - #[tokio::test] - async fn test_transfer_public_to_private_util() { - let api_client = setup_client::().unwrap(); - let private_key = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - - let program_manager = ProgramManager::::new( - Some(private_key), - None, - Some(api_client.clone()), - None, - ) - .unwrap(); - - let program_id = format!("credits.aleo"); - - let recipient = Address::::from_str( - "aleo1wswguyd4gh045y9y2t36ks0wpk4yg3cpeded8cc8fjwud8j7dvystyl9lp", - ) - .unwrap(); - - let transaction_id = program_manager - .transfer( - 7000000, - 0, - recipient, - TransferType::PublicToPrivate, - None, - None, - None, - &program_id, - ) - .unwrap(); - } - - #[tokio::test] - async fn test_inclusion_prover() { - let _res = pre_install_inclusion_prover().await; - } -} diff --git a/backend/src/services/record_handling/utils.rs b/backend/src/services/record_handling/utils.rs deleted file mode 100644 index 0a114293..00000000 --- a/backend/src/services/record_handling/utils.rs +++ /dev/null @@ -1,2092 +0,0 @@ -use avail_common::models::encrypted_data::EncryptedDataTypeCommon; -use chrono::{DateTime, Local}; -use snarkvm::circuit::Aleo; -use snarkvm::console::network::Testnet3; -use snarkvm::ledger::transactions::ConfirmedTransaction; -use snarkvm::prelude::{ - Address, Ciphertext, Entry, Execution, Field, GraphKey, Identifier, Itertools, Literal, - Network, Output, Plaintext, ProgramID, Record, RecordType, Transaction, Transition, Value, - ViewKey, -}; -use snarkvm::synthesizer::program::{Command, Instruction, ProgramCore}; -use snarkvm::utilities::ToBits; -use std::collections::HashMap; -use std::ops::Sub; -use std::str::FromStr; -use tauri::{Manager, Window}; - -use crate::api::{ - aleo_client::{setup_client, setup_local_client}, - encrypted_data::{post_encrypted_data, send_transaction_in}, - fee::{create_record, fetch_record}, - user::name_to_address, -}; - -use crate::helpers::validation::validate_address_bool; -use crate::models::event::EventTransition; -use crate::models::pointers::{ - deployment::DeploymentPointer, - message::TransactionMessage, - record::AvailRecord, - transaction::{ExecutedTransition, TransactionPointer}, -}; -use crate::models::wallet_connect::balance::Balance; - -use crate::models::wallet_connect::records::{GetRecordsRequest, RecordFilterType, RecordsFilter}; -use crate::services::local_storage::encrypted_data::get_encrypted_data_by_flavour; -use crate::services::local_storage::tokens::{ - add_balance, get_balance, get_program_id_for_token, if_token_exists, init_token, -}; -use crate::services::local_storage::{ - encrypted_data::{ - store_encrypted_data, update_encrypted_data_by_id, update_encrypted_data_synced_on_by_id, - update_encrypted_transaction_confirmed_by_id, update_encrypted_transaction_state_by_id, - }, - persistent_storage::{ - get_address, get_address_string, get_backup_flag, get_network, get_username, - }, - session::view::VIEWSESSION, - storage_api::{ - deployment::get_deployment_pointer, - records::{ - check_if_record_exists, encrypt_and_store_records, get_record_pointers, - update_record_spent_local, update_records_spent_backup, - }, - transaction::get_transaction_pointer, - }, -}; -use crate::services::record_handling::transfer::find_confirmed_block_height; - -use avail_common::{ - aleo_tools::program_manager::{Credits, ProgramManager}, - errors::{AvailError, AvailErrorType, AvailResult}, - models::encrypted_data::{EncryptedData, EventTypeCommon, RecordTypeCommon, TransactionState}, - models::{fee_request::FeeRequest, network::SupportedNetworks}, -}; - -use super::decrypt_transition::DecryptTransition; - -/// Gets all tags from a given block height to the latest block height -pub fn get_tags(min_block_height: u32) -> AvailResult> { - let api_client = setup_client::()?; - let latest_height = api_client.latest_height()?; - - let step = 49; - - let mut end_height = latest_height; - let mut start_height = latest_height.sub(step); - - let mut tags: Vec = vec![]; - for _ in (min_block_height..latest_height).step_by(step as usize) { - println!("start_height: {:?}", start_height); - println!("end_height: {:?}", end_height); - let blocks = api_client.get_blocks(start_height, end_height)?; - - let field_tags: Vec<_> = blocks.iter().flat_map(|block| block.tags()).collect(); - let _ = field_tags.iter().map(|tag| tags.push(tag.to_string())); - - end_height = start_height; - start_height = start_height.saturating_sub(step); - } - - Ok(tags) -} - -/// This is to check if a record is spent or not -/// TODO: Needs to be made much faster to be included in txs_sync -> Deprecate -/// Note this is only used in txs_sync just in case the user has spent the records he is receiving already from a different wallet. -fn spent_checker( - block_height: u32, - local_tags: Vec, -) -> AvailResult<(Vec, Vec)> { - let api_client = setup_client::()?; - let latest_height = api_client.latest_height()?; - - let step = 49; - - let mut end_height = latest_height; - let mut start_height = latest_height.sub(step); - - let spent_tags: Vec = vec![]; - for _ in (block_height..latest_height).step_by(step as usize) { - println!("start_height: {:?}", start_height); - println!("end_height: {:?}", end_height); - let blocks = api_client.get_blocks(start_height, end_height)?; - - let tags: Vec<_> = blocks.iter().flat_map(|block| block.tags()).collect(); - - let tags = tags - .iter() - .map(|tag| tag.to_string()) - .collect::>(); - - //check if tags contains any of the local tags and make a vector of bools representing if the local tags are spent or not - let mut result = vec![]; - for local_tag in local_tags.clone() { - if tags.contains(&local_tag) { - result.push(local_tag); - } - } - - // Search in reverse order from the latest block to the earliest block - end_height = start_height; - start_height = start_height.saturating_sub(step); - } - - //check what local tags are not in result and add them as unspent - let mut unspent_tags: Vec = vec![]; - for local_tag in local_tags { - if !spent_tags.contains(&local_tag) { - unspent_tags.push(local_tag); - } - } - - Ok((spent_tags, unspent_tags)) -} - -pub fn transition_to_record( - transition: &Transition, - commitment: &str, - index: u8, -) -> AvailResult<( - Record>, - Record>, - HashMap, -)> { - let v_key = VIEWSESSION.get_instance::()?; - let output = transition.outputs(); - - let record = match output.get(index as usize) { - Some(output) => output.clone().into_record(), - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Record not found".to_string(), - "Record not found".to_string(), - )) - } - }; - - if let Some((r_commitment, record)) = record { - if r_commitment.to_string() == commitment { - let decrypted_record = record.decrypt(&v_key)?; - let data_map = decrypted_record - .data() - .iter() - .map(|(k, v)| (k.to_string(), v.to_string())) - .collect::>(); - Ok((decrypted_record, record, data_map)) - } else { - Err(AvailError::new( - AvailErrorType::Internal, - "Record not found".to_string(), - "Record not found".to_string(), - )) - } - } else { - Err(AvailError::new( - AvailErrorType::Internal, - "Record not found".to_string(), - "Record not found".to_string(), - )) - } -} - -/// Updates spent state of records if the tag matches the transition input tag -pub fn input_spent_check( - transition: &Transition, - spent: bool, -) -> AvailResult> { - let inputs = transition.inputs(); - - let mut spent_ids: Vec = vec![]; - - let filter = RecordsFilter::new( - vec![transition.program_id().to_string()], - None, - RecordFilterType::Unspent, - None, - ); - let get_records_request = GetRecordsRequest::new(None, Some(filter), None); - let (record_pointers, ids) = get_record_pointers::(get_records_request)?; - - for input in inputs { - let input_tag = match input.tag() { - Some(tag) => tag, - None => continue, - }; - - for (record_pointer, id) in record_pointers.iter().zip(ids.iter()) { - if &record_pointer.tag()? == input_tag { - update_record_spent_local::(id, spent)?; - spent_ids.push(id.to_string()); - } - } - } - - Ok(spent_ids) -} - -/// Gets record name from program using the index of the output record -pub fn get_record_name( - program: ProgramCore, Command>, - function_id: &Identifier, - output_index: usize, -) -> AvailResult { - let function = program.get_function(function_id).unwrap(); - - let output = function.outputs()[output_index].clone(); - - Ok(output.value_type().to_string()) -} - -pub fn get_record_type( - program: ProgramCore, Command>, - record_name: String, - record: Record>, -) -> AvailResult { - let mut token_count = 0; - let mut nft_count = 0; - - let functions = program.functions().clone().into_keys(); - for function in functions { - let fn_str = function.to_string(); - match fn_str.as_str() { - _ if fn_str.contains("approve_public") => token_count = token_count + 1, - _ if fn_str.contains("unapprove_public") => token_count = token_count + 1, - _ if fn_str.contains("transfer_from_public") => token_count = token_count + 1, - _ if fn_str.contains("transfer_public") => token_count = token_count + 1, - _ if fn_str.contains("transfer") => token_count = token_count + 1, - _ if fn_str.contains("transfer_private") => token_count = token_count + 1, - _ if fn_str.contains("transfer_private_to_public") => token_count = token_count + 1, - _ if fn_str.contains("transfer_public_to_private") => token_count = token_count + 1, - _ if fn_str.contains("mint") => token_count = token_count + 1, - _ if fn_str.contains("mint_private") => token_count = token_count + 1, - _ if fn_str.contains("split") => token_count = token_count + 1, - _ if fn_str.contains("join") => token_count = token_count + 1, - _ if fn_str.contains("deposit") => token_count = token_count + 1, - _ if fn_str.contains("withdraw") => token_count = token_count + 1, - _ if fn_str.contains("burn") => token_count = token_count + 1, - _ if fn_str.contains("create") => token_count = token_count + 1, - _ if fn_str.contains("init") => token_count = token_count + 1, - - // -------- NFT -------- - _ if fn_str.contains("initialize") => nft_count = nft_count + 1, - _ if fn_str.contains("initialize_collection") => nft_count = nft_count + 1, - _ if fn_str.contains("add_nft") => nft_count = nft_count + 1, - _ if fn_str.contains("admin") => nft_count = nft_count + 1, - _ if fn_str.contains("register") => nft_count = nft_count + 1, - _ if fn_str.contains("minting") => nft_count = nft_count + 1, - _ if fn_str.contains("add_minter") => nft_count = nft_count + 1, - _ if fn_str.contains("update_toggle_settings") => nft_count = nft_count + 1, - _ if fn_str.contains("set_mint_block") => nft_count = nft_count + 1, - _ if fn_str.contains("transfer") => nft_count = nft_count + 1, - _ if fn_str.contains("update_symbol") => nft_count = nft_count + 1, - _ if fn_str.contains("update_base_uri") => nft_count = nft_count + 1, - _ if fn_str.contains("open_mint") => nft_count = nft_count + 1, - _ if fn_str.contains("mint") => nft_count = nft_count + 1, - _ if fn_str.contains("claim_nft") => nft_count = nft_count + 1, - _ if fn_str.contains("claim") => nft_count = nft_count + 1, - _ if fn_str.contains("burn_nft") => nft_count = nft_count + 1, - _ if fn_str.contains("burn") => nft_count = nft_count + 1, - _ => {} - } - } - let mut nft_record_flag = 0; - let mut token_record_flag = 0; - for key in record.data().clone().into_keys() { - match key.to_string().as_str() { - "data" => nft_record_flag = nft_record_flag + 1, - "edition" => nft_record_flag = nft_record_flag + 1, - "amount" => token_record_flag = token_record_flag + 1, - _ => {} - } - } - if (token_count >= 7 && token_record_flag >= 1) { - return Ok(RecordTypeCommon::Tokens); - } else if (nft_count >= 8 && nft_record_flag >= 2) { - return Ok(RecordTypeCommon::NFT); - } else { - return Ok(RecordTypeCommon::None); - } -} - -/// Derives all record pointers from a transition and returns them as a vector -pub fn transition_to_record_pointer( - transaction_id: N::TransactionID, - transition: Transition, - block_height: u32, - view_key: ViewKey, -) -> AvailResult>> { - let address = view_key.to_address(); - let address_x_coordinate = address.to_x_coordinate(); - let sk_tag = GraphKey::try_from(view_key)?.sk_tag(); - let api_client = setup_client::()?; - - let outputs = transition.outputs(); - let mut records: Vec> = vec![]; - - for (index, output) in outputs.iter().enumerate() { - let record = output.clone().into_record(); - - let rp = match record { - Some((commitment, record)) => { - match record.is_owner_with_address_x_coordinate(&view_key, &address_x_coordinate) { - true => { - let record = match record.decrypt(&view_key) { - Ok(record) => record, - Err(_) => { - return Err(AvailError::new( - AvailErrorType::SnarkVm, - "Error decrypting record".to_string(), - "Error decrypting record".to_string(), - )) - } - }; - - match check_if_record_exists::(&record.nonce().to_string())? { - true => continue, - false => {} - } - - let program_id = transition.program_id(); - let mut record_type = RecordTypeCommon::None; - let program = api_client.get_program(program_id)?; - let record_name = - get_record_name(program.clone(), transition.function_name(), index)?; - // check if its in the records table - if if_token_exists(&record_name.clone())? { - if record_name == "credits.record" { - record_type = RecordTypeCommon::AleoCredits; - } else { - record_type = RecordTypeCommon::Tokens; - } - - let balance = get_record_type_and_amount::( - record.clone(), - record_name.clone(), - view_key, - )?; - add_balance::( - record_name.clone().as_str(), - balance.to_string().as_str(), - view_key, - )?; - } else { - record_type = match program_id.to_string().as_str() { - "credits.aleo" => RecordTypeCommon::AleoCredits, - _ => get_record_type( - program.clone(), - record_name.clone(), - record.clone(), - )?, - }; - if record_type == RecordTypeCommon::Tokens - || record_type == RecordTypeCommon::AleoCredits - { - let balance = get_record_type_and_amount::( - record.clone(), - record_name.clone(), - view_key, - )?; - init_token::( - record_name.clone().as_str(), - &program_id.to_string(), - view_key.to_address().to_string().as_str(), - balance.to_string().as_str(), - )?; - } - } - - let record_pointer = AvailRecord::from_record( - commitment, - &record, - sk_tag, - record_type, - &program_id.to_string(), - block_height, - transaction_id, - transition.id().to_owned(), - &transition.function_name().to_string(), - record_name, - index as u8, - &record.owner().to_string(), - )?; - - let encrypted_record_pointer = record_pointer.to_encrypted_data(address)?; - - store_encrypted_data(encrypted_record_pointer)?; - Some(record_pointer) - } - false => None, - } - } - None => None, - }; - - if let Some(rp) = rp { - records.push(rp); - } - } - - Ok(records) -} - -pub fn get_record_type_and_amount( - record: Record>, - record_name: String, - view_key: ViewKey, -) -> AvailResult { - if record.data().clone().is_empty() { - Ok("".to_string()) - } else { - let mut balance = "".to_string(); - for key in record.data().clone().into_keys() { - let is_key: bool = match key.to_string().as_str() { - "amount" => true, - "microcredits" => true, - _ => false, - }; - if is_key { - let balance_entry = match record.data().get(&key.clone()) { - Some(bal) => Ok(bal), - None => Err(()), - }; - let balance_f = match balance_entry.unwrap() { - Entry::Private(Plaintext::Literal(Literal::::U64(amount), _)) => { - let balance_field = amount.to_be_bytes(); - balance = format!("{}u64", u64::from_be_bytes(balance_field).to_string()); - } - Entry::Private(Plaintext::Literal(Literal::::U128(amount), _)) => { - let balance_field = amount.to_be_bytes(); - let bal_t = u128::from_be_bytes(balance_field); - balance = format!("{}u64", u64::try_from(bal_t)?.to_string()); - } - _ => todo!(), - }; - // let balance_field = balance_f.to_be_bytes(); - // balance = format!("{}u64", u64::from_be_bytes(balance_field).to_string()); - } - } - Ok(balance) - } -} - -pub fn output_to_record_pointer( - transaction_id: N::TransactionID, - transition_id: N::TransitionID, - function_id: &Identifier, - program_id: &ProgramID, - output: &Output, - block_height: u32, - view_key: ViewKey, - index: usize, -) -> AvailResult<(Option>, Option)> { - let address_x_coordinate = view_key.to_address().to_x_coordinate(); - let sk_tag = GraphKey::try_from(view_key)?.sk_tag(); - - let record = output.clone().into_record(); - - match record { - Some((commitment, record)) => { - match record.is_owner_with_address_x_coordinate(&view_key, &address_x_coordinate) { - true => { - let record = match record.decrypt(&view_key) { - Ok(record) => record, - Err(_) => return Ok((None, None)), - }; - - match check_if_record_exists::(&record.nonce().to_string())? { - true => return Ok((None, None)), - false => {} - } - - let api_client = setup_client::()?; - let program = api_client.get_program(program_id)?; - let record_name = get_record_name(program.clone(), function_id, index)?; - let mut balance = "".to_string(); - - let mut record_type = RecordTypeCommon::None; - if if_token_exists(&record_name.clone())? { - if record_name.clone() == "credits.record" { - record_type = RecordTypeCommon::AleoCredits; - } else { - record_type = RecordTypeCommon::Tokens; - } - - balance = get_record_type_and_amount::( - record.clone(), - record_name.clone(), - view_key, - )?; - add_balance::( - record_name.clone().as_str(), - balance.to_string().as_str(), - view_key, - )?; - } else { - record_type = match program_id.to_string().as_str() { - "credits.aleo" => RecordTypeCommon::AleoCredits, - _ => get_record_type( - program.clone(), - record_name.clone(), - record.clone(), - )?, - }; - - if record_type == RecordTypeCommon::Tokens - || record_type == RecordTypeCommon::AleoCredits - { - balance = get_record_type_and_amount::( - record.clone(), - record_name.clone(), - view_key, - )?; - init_token::( - record_name.clone().as_str(), - &program_id.to_string(), - view_key.to_address().to_string().as_str(), - balance.to_string().as_str(), - )?; - } - } - let record_pointer = AvailRecord::from_record( - commitment, - &record.clone(), - sk_tag, - record_type, - &program_id.to_string(), - block_height, - transaction_id, - transition_id, - &function_id.to_string(), - record_name.clone(), - index as u8, - &record.owner().to_string(), - )?; - - Ok((Some(record_pointer), Some(balance))) - } - false => Ok((None, None)), - } - } - None => Ok((None, None)), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_all_nft_data() -> AvailResult> { - let network = get_network()?; - - match SupportedNetworks::from_str(network.as_str())? { - SupportedNetworks::Testnet3 => { - let nft_data = get_all_nft_raw::()?; - Ok(nft_data) - } - _ => Err(AvailError::new( - AvailErrorType::Internal, - "Network not supported".to_string(), - "Network not supported".to_string(), - )), - } -} - -pub fn get_all_nft_raw() -> AvailResult> { - let nft_encrypted_data = - get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Record).unwrap(); - let v_key = VIEWSESSION.get_instance::().unwrap(); - - let records = nft_encrypted_data - .iter() - .map(|x| { - let encrypted_data = x.to_enrypted_struct::().unwrap(); - let block: AvailRecord = encrypted_data.decrypt(v_key).unwrap(); - block - }) - .collect::>>(); - - let plaintexts: Vec>> = records - .iter() - .filter(|&record| record.metadata.record_type == RecordTypeCommon::NFT) // NFT Records - .filter_map(|record: &AvailRecord| match record.to_record() { - Ok(record) => Some(record), - Err(e) => None, - }) - .collect::>(); - - fn u128_to_string(u: u128) -> String { - let mut temp_u128 = u; - let mut bytes = vec![] as Vec; - - while temp_u128 > 0u128 { - let byte = (temp_u128 & 0xff) as u8; - bytes.push(byte); - temp_u128 >>= 8; - } - - bytes.reverse(); - - String::from_utf8(bytes).unwrap() - } - - let full_urls = plaintexts - .iter() - .filter_map(|record| { - let data1 = record - .data() - .clone() - .get(&Identifier::::from_str("data1").unwrap()) - .cloned()?; - - let data2 = record - .data() - .clone() - .get(&Identifier::::from_str("data2").unwrap()) - .cloned()?; - - match (data1, data2) { - ( - Entry::Private(Plaintext::Literal(Literal::::U128(data1), _)), - Entry::Private(Plaintext::Literal(Literal::::U128(data2), _)), - ) => { - let data1 = u128_to_string(*data1); - let data2 = u128_to_string(*data2); - Some(format!("{}{}", data1, data2)) - } - _ => None, - } - }) - .collect::>(); - - Ok(full_urls) -} - -/// Helper to parse the mapping value from the program mapping -fn parse_with_suffix(input: &str) -> Result { - //remove last three characters - let input = &input[..input.len() - 3]; - input.parse::() -} - -/// Get public balance for any ARC20 token -pub fn get_public_token_balance(asset_id: &str) -> AvailResult { - let address = get_address_string()?; - let record_name = format!("{}.record", asset_id); - // let program_id = format!("{}.aleo", asset_id); - let mut program_id = get_program_id_for_token(&record_name)?; - if (program_id == "") { - program_id = format!("{}.aleo", asset_id); - } - println!("===> PROGRAM ID FOR FETCH {:?}", program_id); - let api_client = setup_client::()?; - - let credits_mapping = match api_client.get_mapping_value(program_id, "account", &address) { - Ok(credits_mapping) => credits_mapping, - Err(e) => match e.to_string().as_str() { - "Mapping not found" => return Ok(0.0), - _ => return Err(e.into()), - }, - }; - - let pub_balance = parse_with_suffix(&credits_mapping.to_string())? as f64; - - println!("pub_balance: {:?}", pub_balance); - - Ok(pub_balance / 1000000.0) -} - -/// Get private balance for any ARC20 token -pub fn get_private_token_balance(asset_id: &str) -> AvailResult { - let address = get_address_string()?; - let record_name = format!("{}.record", asset_id); - let program_id = format!("{}.aleo", asset_id); - println!("===> Asset ID in get_private_balance() {:?}", asset_id); - - let vk = VIEWSESSION.get_instance::()?; - let balance = get_balance(&record_name, vk)?; - - println!("balance: {:?}", balance); - let balance_trimmed = balance.trim_end_matches("u64"); - - Ok(balance_trimmed.parse::()? as f64 / 1000000.0) -} - -/// Get Arc20 Token Balance -pub fn get_token_balance(asset_id: &str) -> AvailResult { - let asset_id_modified = asset_id.to_string(); - let asset_id_final = asset_id.to_string().replace(".record", ""); - println!("===> Asset ID after mpod {:?}", asset_id_final); - let public = get_public_token_balance::(&asset_id_final)?; - let private = get_private_token_balance::(&asset_id_final)?; - println!("===> Token Balance of {:?}", asset_id_final); - println!("public: {:?}", public); - println!("private: {:?}", private); - - Ok(Balance::new(public, private)) -} - -/// Handles encrypted message passing and updated transaction state -pub async fn handle_encrypted_storage_and_message( - transaction_id: N::TransactionID, - recipient_address: Address, - transaction_pointer_id: &str, - input_id: Option, - fee_id: Option, - wallet_connect: bool, - window: Option, -) -> AvailResult<()> { - let username = get_username()?; - let backup = get_backup_flag()?; - let view_key = VIEWSESSION.get_instance::()?; - - let sender_address = get_address::()?; - - let mut processing_transaction_pointer = get_transaction_pointer::(transaction_pointer_id)?; - processing_transaction_pointer.update_pending_transaction(); - - let encrypted_pending_transaction = - processing_transaction_pointer.to_encrypted_data(sender_address)?; - - update_encrypted_transaction_state_by_id( - transaction_pointer_id, - &encrypted_pending_transaction.ciphertext, - &encrypted_pending_transaction.nonce, - TransactionState::Pending, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &transaction_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - // search for the transaction on chain - let ( - block_height, - transitions, - timestamp, - transaction_state, - fee_tx_id, - rejected_execution, - fee, - ) = find_confirmed_block_height::(transaction_id)?; - - println!("State of transaction: {:?}", transaction_state); - - if transaction_state == TransactionState::Rejected { - // input record was not spent in this case - if let Some(input_id) = input_id { - update_record_spent_local::(&input_id, false)?; - } - - //TODO - Do not double subtract input id - handle_transaction_rejection( - processing_transaction_pointer, - transaction_pointer_id, - rejected_execution, - fee_tx_id, - block_height, - fee, - sender_address, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &transaction_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - // Check for remainder of private fee given back as new record - for transition in transitions { - transition_to_record_pointer(transaction_id, transition, block_height, view_key)?; - } - - return Ok(()); - } else if transaction_state == TransactionState::Aborted { - // records were not spent in this case - if let Some(input_id) = input_id { - update_record_spent_local::(&input_id, false)?; - } - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, false)?; - } - - processing_transaction_pointer.update_aborted_transaction( - "Transaction aborted by the Aleo blockchain. No tokens were spent.".to_string(), - transaction_id, - block_height, - ); - - let updated_encrypted_transaction = - processing_transaction_pointer.to_encrypted_data(sender_address)?; - - update_encrypted_transaction_state_by_id( - transaction_pointer_id, - &updated_encrypted_transaction.ciphertext, - &updated_encrypted_transaction.nonce, - TransactionState::Aborted, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &transaction_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - return Ok(()); - } - - let mut execution_transitions: Vec> = vec![]; - let mut spent_ids: Vec = vec![]; - - let records = transitions - .iter() - .filter(|transition| !transition.is_fee_public()) - .map(|transition| { - let transition = transition.to_owned(); - - if !transition.is_fee_private() { - if wallet_connect { - let mut transition_spent_ids = match input_spent_check::(&transition, true) { - Ok(transition_spent_ids) => transition_spent_ids, - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Error checking input spent".to_string(), - )) - } - }; - - spent_ids.append(&mut transition_spent_ids); - } - - let executed_transition = ExecutedTransition::::new( - transition.program_id().to_string(), - transition.function_name().to_string(), - transition.id().to_owned(), - ); - - execution_transitions.push(executed_transition); - } - - let record_pointers = - transition_to_record_pointer(transaction_id, transition, block_height, view_key)?; - - println!("record_pointers found from transfer: {:?}", record_pointers); - - Ok(record_pointers) - }) - .collect::>>>>()? - .concat(); - - handle_transaction_confirmed::( - transaction_pointer_id, - transaction_id, - execution_transitions, - block_height, - timestamp, - fee, - sender_address, - )?; - - println!("Inshallah confirmed"); - let mut confirmed_transaction_pointer = get_transaction_pointer::(transaction_pointer_id)?; - println!("{:?}", confirmed_transaction_pointer); - - //check if private fee was spent - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, true)?; - if backup { - spent_ids.push(fee_id); - } - } - - //update token input was spent - if let Some(input_id) = input_id { - update_record_spent_local::(&input_id, true)?; - if backup { - spent_ids.push(input_id); - } - } - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &transaction_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - if sender_address != recipient_address { - let transaction_message = TransactionMessage::::new( - transaction_id, - block_height, - username, - processing_transaction_pointer.message(), - ); - - let encrypted_transaction_message = - transaction_message.to_encrypted_data(recipient_address)?; - - send_transaction_in(encrypted_transaction_message).await?; - } - - Ok(()) -} - -/// Handles updating pending transaction and encrypted storage -pub async fn handle_transaction_update_and_encrypted_storage( - transaction_id: N::TransactionID, - transaction_pointer_id: &str, - fee_id: Option, - window: Option, -) -> AvailResult<()> { - let backup = get_backup_flag()?; - let view_key = VIEWSESSION.get_instance::()?; - - let sender_address = get_address::()?; - - // Update transaction to pending to confirm - let mut processing_transaction_pointer = get_transaction_pointer::(transaction_pointer_id)?; - processing_transaction_pointer.update_pending_transaction(); - - let encrypted_pending_transaction = - processing_transaction_pointer.to_encrypted_data(sender_address)?; - - update_encrypted_transaction_state_by_id( - transaction_pointer_id, - &encrypted_pending_transaction.ciphertext, - &encrypted_pending_transaction.nonce, - TransactionState::Pending, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &transaction_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - let ( - block_height, - transitions, - timestamp, - transaction_state, - fee_tx_id, - rejected_execution, - fee, - ) = find_confirmed_block_height::(transaction_id)?; - - if transaction_state == TransactionState::Rejected { - // Check for remainder of private fee given back as new record - for transition in transitions { - transition_to_record_pointer(transaction_id, transition, block_height, view_key)?; - } - - handle_transaction_rejection( - processing_transaction_pointer, - transaction_pointer_id, - rejected_execution, - fee_tx_id, - block_height, - fee, - sender_address, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &transaction_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - return Ok(()); - } else if transaction_state == TransactionState::Aborted { - // fee was not consumed in this case - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, false)?; - } - - //TODO - Update record spent state for input nonces - - processing_transaction_pointer.update_aborted_transaction( - "Transaction aborted by the Aleo blockchain. No tokens were spent.".to_string(), - transaction_id, - block_height, - ); - let updated_encrypted_transaction = - processing_transaction_pointer.to_encrypted_data(sender_address)?; - update_encrypted_transaction_state_by_id( - transaction_pointer_id, - &updated_encrypted_transaction.ciphertext, - &updated_encrypted_transaction.nonce, - TransactionState::Aborted, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &transaction_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - return Ok(()); - } - - let mut execution_transitions: Vec> = vec![]; - let mut spent_ids: Vec = vec![]; - - let records = transitions - .iter() - .filter(|transition| !transition.is_fee_public()) - .map(|transition| { - let transition = transition.to_owned(); - - if !transition.is_fee_private() { - let mut transition_spent_ids = input_spent_check::(&transition, true)?; - spent_ids.append(&mut transition_spent_ids); - - let executed_transition = ExecutedTransition::::new( - transition.program_id().to_string(), - transition.function_name().to_string(), - transition.id().to_owned(), - ); - - execution_transitions.push(executed_transition); - } - - let record_pointer = - transition_to_record_pointer(transaction_id, transition, block_height, view_key)?; - Ok(record_pointer) - }) - .collect::>>>>()? - .concat(); - - handle_transaction_confirmed::( - transaction_pointer_id, - transaction_id, - execution_transitions, - block_height, - timestamp, - fee, - sender_address, - )?; - - //TODO - Do not double subtract fee - //check if private fee was spent - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, true)?; - if backup { - spent_ids.push(fee_id); - } - } - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &transaction_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - Ok(()) -} - -// TODO - Handle fee remainder for deployment handler -/// Handles updating deployment transaction and encrypted storage -pub async fn handle_deployment_update_and_encrypted_storage( - transaction_id: N::TransactionID, - deployment_pointer_id: &str, - fee_id: Option, - window: Option, -) -> AvailResult<()> { - let backup = get_backup_flag()?; - let sender_address = get_address::()?; - let view_key = VIEWSESSION.get_instance::()?; - - // Update transaction to pending to confirm - let mut processing_deployment_pointer = get_deployment_pointer::(deployment_pointer_id)?; - processing_deployment_pointer.update_pending_deployment(); - - let encrypted_pending_deployment = - processing_deployment_pointer.to_encrypted_data(sender_address)?; - - update_encrypted_transaction_state_by_id( - deployment_pointer_id, - &encrypted_pending_deployment.ciphertext, - &encrypted_pending_deployment.nonce, - TransactionState::Pending, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &deployment_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - let (block_height, transitions, _, transaction_state, _fee_tx_id, _, fee) = - find_confirmed_block_height::(transaction_id)?; - - if transaction_state == TransactionState::Rejected { - for transition in transitions { - input_spent_check(&transition, true)?; - transition_to_record_pointer( - transaction_id, - transition.clone(), - block_height, - view_key, - )?; - } - - handle_deployment_rejection( - processing_deployment_pointer, - deployment_pointer_id, - transaction_id, - block_height, - fee, - sender_address, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &deployment_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - return Ok(()); - } else if transaction_state == TransactionState::Aborted { - // fee was not consumed in this case - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, false)?; - } - - processing_deployment_pointer.update_aborted_deployment( - "Transaction aborted by the Aleo blockchain. No tokens were spent.".to_string(), - transaction_id, - block_height, - ); - let updated_encrypted_deployment = - processing_deployment_pointer.to_encrypted_data(sender_address)?; - update_encrypted_transaction_state_by_id( - deployment_pointer_id, - &updated_encrypted_deployment.ciphertext, - &updated_encrypted_deployment.nonce, - TransactionState::Aborted, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &deployment_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - return Ok(()); - } - - //checking for remainder if private fee was spent - for transition in transitions { - input_spent_check(&transition, true)?; - transition_to_record_pointer(transaction_id, transition.clone(), block_height, view_key)?; - } - - handle_deployment_confirmed( - deployment_pointer_id, - transaction_id, - block_height, - fee, - sender_address, - )?; - - // if record was spent on fee update state - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, true)?; - - if backup { - update_records_spent_backup::(vec![fee_id]).await?; - } - } - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &deployment_pointer_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - }; - - Ok(()) -} - -pub fn handle_deployment_confirmed( - pointer_id: &str, - tx_id: N::TransactionID, - block_height: u32, - fee: Option, - sender_address: Address, -) -> AvailResult<()> { - let mut pending_transaction_pointer = get_deployment_pointer::(pointer_id)?; - - pending_transaction_pointer.update_confirmed_deployment(tx_id, block_height, fee); - let updated_encrypted_transaction = - pending_transaction_pointer.to_encrypted_data(sender_address)?; - - update_encrypted_data_by_id( - pointer_id, - &updated_encrypted_transaction.ciphertext, - &updated_encrypted_transaction.nonce, - )?; - - Ok(()) -} - -pub fn handle_deployment_rejection( - mut pointer: DeploymentPointer, - pointer_id: &str, - tx_id: N::TransactionID, - block_height: u32, - fee: Option, - sender_address: Address, -) -> AvailResult<()> { - pointer.update_rejected_deployment( - "Transaction rejected by the Aleo blockchain.".to_string(), - Some(tx_id), - block_height, - fee, - ); - - let updated_encrypted_deployment = pointer.to_encrypted_data(sender_address)?; - - update_encrypted_transaction_state_by_id( - pointer_id, - &updated_encrypted_deployment.ciphertext, - &updated_encrypted_deployment.nonce, - TransactionState::Rejected, - )?; - - Ok(()) -} - -pub fn handle_transaction_rejection( - mut pointer: TransactionPointer, - pointer_id: &str, - rejected_execution: Option>, - tx_id: Option, - block_height: u32, - fee: Option, - sender_address: Address, -) -> AvailResult<()> { - // NOTE - If bugs out change to update via input nonces - if let Some(rejected_execution) = rejected_execution { - let rejected_transitions = rejected_execution.transitions(); - - for transition in rejected_transitions { - if !transition.is_fee_private() { - input_spent_check::(transition, false)?; - } - } - } - - pointer.update_rejected_transaction( - "Transaction rejected by the Aleo blockchain.".to_string(), - tx_id, - block_height, - fee, - ); - - let updated_encrypted_transaction = pointer.to_encrypted_data(sender_address)?; - - update_encrypted_transaction_state_by_id( - pointer_id, - &updated_encrypted_transaction.ciphertext, - &updated_encrypted_transaction.nonce, - TransactionState::Rejected, - )?; - - Ok(()) -} - -pub fn handle_transaction_confirmed( - transaction_pointer_id: &str, - tx_id: N::TransactionID, - execution_transitions: Vec>, - block_height: u32, - timestamp: DateTime, - fee: Option, - sender_address: Address, -) -> AvailResult<()> { - let mut pending_transaction_pointer = get_transaction_pointer::(transaction_pointer_id)?; - - pending_transaction_pointer.update_confirmed_transaction( - tx_id, - block_height, - execution_transitions, - timestamp, - TransactionState::Confirmed, - fee, - ); - - let updated_encrypted_transaction = - pending_transaction_pointer.to_encrypted_data(sender_address)?; - - let program_ids = match updated_encrypted_transaction.clone().program_ids { - Some(program_ids) => program_ids, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Program ids not found".to_string(), - "Program ids not found".to_string(), - )) - } - }; - - let function_ids = match updated_encrypted_transaction.clone().function_ids { - Some(function_ids) => function_ids, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Function ids not found".to_string(), - "Function ids not found".to_string(), - )) - } - }; - - update_encrypted_transaction_confirmed_by_id( - transaction_pointer_id, - &updated_encrypted_transaction.ciphertext, - &updated_encrypted_transaction.nonce, - &program_ids, - &function_ids, - )?; - - Ok(()) -} - -/// Sync transaction whilst scanning blocks -pub fn sync_transaction( - transaction: &ConfirmedTransaction, - block_height: u32, - timestamp: DateTime, - message: Option, - from: Option, -) -> AvailResult<( - Option, - Vec>, - Vec, - bool, -)> { - let view_key = VIEWSESSION.get_instance::()?; - let address = view_key.to_address(); - - let mut record_pointers: Vec> = vec![]; - let mut encrypted_transition_pointers: Vec = vec![]; - - let mut execution_transitions: Vec> = vec![]; - let mut found_flag = false; - - let state = check_transaction_state::(transaction)?; - - for transition in transaction.transitions() { - let ownership_check = match DecryptTransition::owns_transition( - view_key, - *transition.tpk(), - *transition.tcm(), - ) { - Ok(res) => res, - Err(_e) => false, - }; - - if ownership_check { - input_spent_check(&transition.clone(), true)?; - - let execution_transition = ExecutedTransition::::new( - transition.program_id().to_string(), - transition.function_name().to_string(), - transition.id().to_owned(), - ); - - if !transition.is_fee_private() && !transition.is_fee_public() { - execution_transitions.push(execution_transition); - } - - let mut transition_record_pointers = transition_to_record_pointer::( - transaction.id().to_owned(), - transition.clone(), - block_height, - view_key, - )?; - - record_pointers.append(&mut transition_record_pointers); - } else { - let (mut transition_record_pointers, mut encrypted_transitions, _transition_spent_ids) = - DecryptTransition::check_inputs_outputs_inclusion::( - view_key, - transition.clone(), - transaction.id().to_owned(), - timestamp, - block_height, - message.clone(), - from.clone(), - )?; - - record_pointers.append(&mut transition_record_pointers); - if !transition.is_fee_private() && !transition.is_fee_public() { - encrypted_transition_pointers.append(&mut encrypted_transitions); - } - - found_flag = true; - } - } - - let execution_transaction = match !execution_transitions.is_empty() { - true => { - let inner_tx = transaction.transaction(); - let fee = match inner_tx.fee_amount() { - Ok(fee) => *fee as f64 / 1000000.0, - Err(_) => { - return Err(AvailError::new( - AvailErrorType::SnarkVm, - "Error calculating fee".to_string(), - "Issue calculating fee".to_string(), - )) - } - }; - - println!("Fee found from external execution: {:?}", fee); - - let execution_tx = TransactionPointer::::new( - None, - Some(transaction.id().to_owned()), - state, - Some(block_height), - None, - None, - execution_transitions, - vec![], - timestamp, - Some(timestamp), - None, - EventTypeCommon::Execute, - None, - Some(fee), - None, - ); - - let encrypted_exec_tx = execution_tx.to_encrypted_data(address)?; - store_encrypted_data(encrypted_exec_tx.clone())?; - - found_flag = true; - - Some(encrypted_exec_tx) - } - false => None, - }; - - Ok(( - execution_transaction, - record_pointers, - encrypted_transition_pointers, - found_flag, - )) -} - -pub fn check_transaction_state( - transaction: &ConfirmedTransaction, -) -> AvailResult { - if let ConfirmedTransaction::::AcceptedExecute(_, _, _) = transaction { - Ok(TransactionState::Confirmed) - } else if let ConfirmedTransaction::::AcceptedDeploy(_, _, _) = transaction { - Ok(TransactionState::Confirmed) - } else if let ConfirmedTransaction::::RejectedExecute(_, _, _, _) = transaction { - //TODO - Return rejected execution - - Ok(TransactionState::Rejected) - } else if let ConfirmedTransaction::::RejectedDeploy(_, _, _, _) = transaction { - Ok(TransactionState::Rejected) - } else { - Ok(TransactionState::Pending) - } -} - -pub fn get_executed_transitions( - transaction: &Transaction, - block_height: u32, -) -> AvailResult>> { - let view_key = VIEWSESSION.get_instance::()?; - let mut execution_transitions: Vec> = vec![]; - - for transition in transaction.transitions() { - input_spent_check(transition, true)?; - - let ownership_check = match DecryptTransition::owns_transition( - view_key, - *transition.tpk(), - *transition.tcm(), - ) { - Ok(res) => res, - Err(_e) => false, - }; - - if ownership_check { - let execution_transition = ExecutedTransition::::new( - transition.program_id().to_string(), - transition.function_name().to_string(), - transition.id().to_owned(), - ); - - if !transition.is_fee_private() && !transition.is_fee_public() { - execution_transitions.push(execution_transition); - } - - transition_to_record_pointer( - transaction.id(), - transition.clone(), - block_height, - view_key, - )?; - } - } - - Ok(execution_transitions) -} - -pub fn get_fee_transition( - transaction_id: N::TransactionID, -) -> AvailResult { - let view_key = VIEWSESSION.get_instance::()?; - let api_client = setup_client::()?; - - let transaction = match api_client.get_transaction(transaction_id) { - Ok(transaction) => transaction, - Err(_) => { - return Err(AvailError::new( - AvailErrorType::Node, - "Transaction not found".to_string(), - "Transaction not found".to_string(), - )) - } - }; - let fee_transition = transaction.fee_transition(); - - match fee_transition { - Some(fee_transition) => { - let transition = fee_transition.transition(); - let (inputs, outputs) = - DecryptTransition::decrypt_inputs_outputs(view_key, transition)?; - let fee_event_transition = EventTransition::new( - transition.id().to_string(), - transition.program_id().to_string(), - transition.function_name().to_string(), - inputs, - outputs, - ); - Ok(fee_event_transition) - } - None => Err(AvailError::new( - AvailErrorType::Internal, - "Fee transition not found".to_string(), - "Fee transition not found".to_string(), - )), - } -} - -pub async fn get_address_from_recipient(recipient: &str) -> AvailResult> { - match validate_address_bool(recipient) { - true => { - let address = Address::::from_str(recipient)?; - Ok(address) - } - false => name_to_address(recipient).await, - } -} - -/* --Wallet Connect Utilities-- */ - -pub fn to_commitment( - record: Record>, - program_id: &ProgramID, - record_name: &Identifier, -) -> AvailResult> { - //construct the input as `(program_id || record_name || record)`. - let mut input = program_id.to_bits_le(); - record_name.write_bits_le(&mut input); - record.write_bits_le(&mut input); - - //Compute the BHP hash of the program record input. - let commitment = match N::hash_bhp1024(&input) { - Ok(commitment) => commitment, - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - e.to_string(), - "Record input commitment not found".to_string(), - )) - } - }; - - Ok(commitment) -} - -pub fn parse_inputs( - inputs: Vec, - function_identifier: &str, -) -> AvailResult<(Vec>, Vec, Option>, Option)> { - // check if input is address - let mut values: Vec> = vec![]; - let mut nonces: Vec = vec![]; - let mut recipient_address: Option> = None; - let mut amount = None; - - for (_index, input) in inputs.iter().enumerate() { - // Check if value is address - if validate_address_bool(input) { - recipient_address = Some(Address::::from_str(input)?); - let value = Value::from_str(input)?; - values.push(value); - } else { - //check if value is record - match Record::>::from_str(input) { - Ok(record) => { - let nonce = record.nonce().to_string(); - nonces.push(nonce); - let value = Value::Record(record); - values.push(value); - } - Err(_) => { - let value = Value::from_str(input)?; - values.push(value); - - // value is constant plaintext input - if function_identifier.contains("transfer") { - let trimmed_input = input.trim_end_matches("u64"); - - if let Ok(amount_found) = trimmed_input.parse::() { - amount = Some(amount_found as f64 / 1000000.0); - } - } - } - } - } - } - - Ok((values, nonces, recipient_address, amount)) -} - -pub async fn estimate_fee( - program_id: &str, - function_id: &str, - inputs: Vec>, - program_manager: ProgramManager, -) -> AvailResult -where - N: Network, - A: Aleo, -{ - // Get the program from chain, error if it doesn't exist - let program = program_manager.api_client()?.get_program(program_id)?; - - let function_identifier = Identifier::::from_str(function_id)?; - // API Call to see if record already exists - let _fee_value = 0i32; - let _if_exists = true; - match fetch_record(program_id.to_string(), function_id.to_string()).await? { - // Return the fee amount if the record exists - Some(x) => Ok(u64::try_from(x)?), - // Estimate the fee and also initiate an API call to Fee Estimation Microservice to create a record for the program. - None => { - let (fee, (_storage_fee, _namespace_fee), execution) = program_manager - .estimate_execution_fee::(&program, function_identifier, inputs.iter())?; - let execution_vector = - FeeRequest::to_bytes_execution_object::(execution.clone()).await; - match execution_vector { - Ok(execution_vec) => { - let request = FeeRequest::new( - execution_vec, - program_id.to_string(), - function_id.to_string(), - SupportedNetworks::Testnet3, - ); - println!("Sending a request to Avail's Fee Estimation Microservice to add the fee data"); - let result: String = create_record(request).await?; - println!("{:?}", result); - } - Err(_e) => (), - } - println!("Execution Fee: {}", fee); - Ok(fee) - } - } -} - -// ======================================================== TESTS ======================================================== -#[cfg(test)] -mod test { - use std::{ - fmt::format, - ptr::null, - time::{Duration, Instant}, - }; - - use avail_common::{ - aleo_tools::{ - api::AleoAPIClient, - test_utils::{AVAIL_NFT_TEST, RECORD_NFT_CLAIM, RECORD_NFT_MINT, TOKEN_MINT}, - }, - models::constants::{ - TESTNET3_ADDRESS, TESTNET3_PRIVATE_KEY, TESTNET_ADDRESS, TESTNET_PRIVATE_KEY, - }, - }; - use snarkvm::{ - circuit::{environment::Private, AleoV0}, - prelude::{Parser, PrivateKey, Transaction}, - synthesizer::Program, - }; - use tokio::time::sleep; - - use crate::{models::pointers::record::Metadata, services::local_storage::tokens::get_balance}; - - use super::*; - use snarkvm::prelude::Testnet3; - #[tokio::test] - async fn test_get_all_nft_data() { - let res = get_all_nft_data().unwrap(); - println!("res\n {:?}", res); - } - // #[tokio::test] - // async fn test_token_record() { - // let mut api_client = setup_client::().unwrap(); - // let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - // let pk_3 = PrivateKey::::from_str(TESTNET3_PRIVATE_KEY).unwrap(); - // let vk = ViewKey::::try_from(pk).unwrap(); - // let vk_3 = ViewKey::::try_from(pk_3).unwrap(); - // let fee = 10000u64; - // let program_id = "token_avl_4.aleo"; - // // INPUTS - // let address_to_mint = Value::::try_from(TESTNET3_ADDRESS).unwrap(); - // let amt_input = Value::::try_from("100u64").unwrap(); - // let transfer_amt = Value::::try_from("1u64").unwrap(); - // let fee = 10000u64; - - // // let token_program = Program::::from_str(TOKEN_PROGRAM).unwrap(); - // let token_mint_program = Program::::from_str(TOKEN_MINT).unwrap(); - // let mut program_manager = - // ProgramManager::::new(Some(pk), None, Some(api_client.clone()), None) - // .unwrap(); - // let mut program_manager_3 = - // ProgramManager::::new(Some(pk_3), None, Some(api_client.clone()), None) - // .unwrap(); - // // program_manager.add_program(&token_program); - // program_manager.add_program(&token_mint_program); - // program_manager_3.add_program(&token_mint_program); - - // STEP - 0 DEPLOY PROGRAM (DONT NEED TO DEPLOY AGAIN) - // let deployement_id = program_manager.deploy_program("token_avl_4.aleo", 10000u64, None, None).unwrap(); - // println!("----> Program Deployed - {:?}", deployement_id); - // let mint_program: Result, Command>, snarkvm::prelude::Error> = api_client.get_program("token_avl.aleo"); - - // STEP - 1 MINT ****ONLY FOR TESTING PURPOSES**** - // let inputs = vec![address_to_mint.clone(), amt_input.clone()]; - // let mint_tokens = program_manager.execute_program(program_id, "mint_public", inputs.iter(), fee, None, None).unwrap().to_string(); - // println!("----> Tokens Minted - {:?}", mint_tokens); - - // let mint_txn = api_client.get_transaction(::TransactionID::from_str("at17hlupnq8nutyzvdccj5smhf6s8u7yzplwjf38xzqgl93486r3c8s9mrhuc").unwrap()).unwrap(); - // println!("----> Mint Tokens TXN - {:?}", mint_txn); - - // STEP - 2 QUERY MAPPING TO VERIFY - // let mapping_op = program_manager.get_mapping_value(program_id, "account", TESTNET3_ADDRESS).unwrap(); - // println!("----> Mapping Value - {:?}", mapping_op); - - // STEP - 4 PREPARE TOKEN RECORD BY USING transfer_public_to_private() fn - // let inputs = vec![address_to_mint.clone(), transfer_amt.clone()]; - // let token_record = program_manager_3.execute_program(program_id, "transfer_public_to_private", inputs.iter(),fee, None, None).unwrap().to_string(); - // let record_txn = api_client.get_transaction(::TransactionID::from_str(&token_record).unwrap()).unwrap(); - - // println!("----> Token Record TXN - {:?}", record_txn); - - // let record_txn_id = ::TransactionID::from_str("at18r5vumc27swqw0vtm9gp4la0cwg8nxk4njm49sp2dj7anp596c9qgaz66w").unwrap(); - // let record_txn = api_client.get_transaction(::TransactionID::from_str("at18r5vumc27swqw0vtm9gp4la0cwg8nxk4njm49sp2dj7anp596c9qgaz66w").unwrap()).unwrap(); - // // println!("----> Token Record TXN - {:?}", record_txn); - // let mut latest_height = api_client.latest_height().unwrap(); - // for transition in record_txn.clone().into_transitions(){ - // println!("INN"); - // if transition.program_id().to_string() == program_id { - // println!("OKK"); - // let record_pointer_token = transition_to_record_pointer::(record_txn.clone().id(), transition.clone(), latest_height, vk_3).unwrap(); - - // println!("----> Token Record - {:?}", record_pointer_token); - // } - // } - - // STEP - 4 QUERY LOCAL STORAGE TO VERIFY - // let mapping_op = program_manager - // .get_mapping_value(program_id, "account", TESTNET3_ADDRESS) - // .unwrap(); - // println!("----> Mapping Value - {:?}", mapping_op); - // let local_db_value = get_balance("token_avl_4.record", vk_3).unwrap(); - // println!("----> Local DB Value - {:?}", local_db_value); - // } - - // #[test] - // fn test_get_private_balance() { - // let _res = get_private_token_balance::("credits").unwrap(); - - // println!("res: {:?}", _res); - // } - - // #[test] - // fn get_public_balance() { - // get_public_token_balance::("credits").unwrap(); - // } - - // #[tokio::test] - // async fn test_estimate_fee() { - - // let program_id = "credits.aleo"; - // let function_id = "transfer_public"; - - // let inputs = vec![ - // // Value::::try_from(TESTNET_ADDRESS).unwrap(), - // Value::::try_from(TESTNET3_ADDRESS).unwrap(), - // Value::::try_from("10000u64").unwrap(), - // // Value::::try_from("true").unwrap() - // ]; - - // //let inputs = vec![]; - - // let api_client = setup_client::().unwrap(); - - // let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - // let program_manager = - // ProgramManager::::new(Some(pk), None, Some(api_client), None).unwrap(); - // let start = Instant::now(); - // let res = - // estimate_fee::(program_id, function_id, inputs, program_manager) - // .await.unwrap(); - // println!("ELAPSED TIME: {:?}",start.elapsed()); - // println!("res: {:?}", res); - // } - // } - - // #[tokio::test] - // async fn test_nft_record(){ - // // ARRANGE - // let mut api_client = setup_client::().unwrap(); - // // ALEO INPUTS - // let program_id = "avail_nft_0.aleo"; - // let nft_program = Program::::from_str(AVAIL_NFT_TEST).unwrap(); - // let total = Value::::try_from("10u128").unwrap(); - // let symbol = Value::::try_from("19212u128").unwrap(); - // let token_id = Value::::try_from("{ - // data1: 146324u128, - // data2: 823446u128 - // }").unwrap(); - // let base_uri = Value::::try_from("{ - // data0: 143324u128, - // data1: 883746u128, - // data2: 993843u128, - // data3: 932838u128 - // }").unwrap(); - // let edition = Value::::try_from("0scalar").unwrap(); - // let owner = Value::::try_from(TESTNET_ADDRESS).unwrap(); - // let amount = Value::::try_from("3u8").unwrap(); - // let settings = Value::::try_from("3u32").unwrap(); - // let block = Value::::try_from("64400u32").unwrap(); //UPDATE ASPER VALUE - // let hiding_nonce = Value::::try_from("1234scalar").unwrap(); - // // let record_NFT_mint = Value::::Record(Record::>::from_str(RECORD_NFT_MINT).unwrap()); - // // let record_NFT_claim = Value::::Record(Record::>::from_str(RECORD_NFT_CLAIM).unwrap()); - // // Program manager - // let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - // let vk = ViewKey::::try_from(pk).unwrap(); - // let fee = 10000u64; - // let mut program_manager = - // ProgramManager::::new(Some(pk), None, Some(api_client.clone()), None).unwrap(); - // program_manager.add_program(&nft_program); - // // ACT - // // ============================== DOCUMENTATION FOR TESTING ============================== - // // STEP - 0 DEPLOY PROGRAM (DONT NEED TO DEPLOY AGAIN) - // // let deployement_id = program_manager.deploy_program(program_id, 10000u64, None, None).unwrap(); - // // println!("----> Program Deployed - {:?}", deployement_id); - - // let program = program_manager.get_program(program_id).unwrap(); - - // // ALEO FUNCTIONS EXECUTION FLOW STARTS HERE - // // Comment out steps that you finish executing - // // STEP - 1 initialize_collection() - // // let init_inputs = vec![total.clone(), symbol.clone(), base_uri.clone()]; - // // let init_txn_id = program_manager.execute_program(program_id, "initialize_collection", init_inputs.iter(), 10000u64, None, None).unwrap().to_string(); - // // println!("----> Initialised a NFT Collection (TXN-ID) - {:?}", init_txn_id); - - // // // STEP - 2 add_nft() - // // let add_nft_inputs = vec![token_id.clone(), edition.clone()]; - // // let add_nft_txn_id = program_manager.execute_program(program_id, "add_nft", add_nft_inputs.iter(), fee, None, None).unwrap().to_string(); - // // println!("----> Added a NFT to the Collection (TXN-ID) - {:?}", add_nft_txn_id); - - // // // Get the txn_id from the output and get_transaction() using the output - // // // STEP - 3 add_minter() - // // let add_minter_inputs = vec![owner.clone(), amount.clone()]; - // // let add_minter_txn_id = program_manager.execute_program(program_id, "add_minter", add_minter_inputs.iter(), fee, None, None).unwrap().to_string(); - // // println!("----> Added a Minter to the Collection (TXN-ID) - {:?}", add_nft_txn_id); - // // sleep(Duration::from_secs(20)).await; - // // println!("Waited 20 secs for the TXN to Broadcast "); - // let add_minter_txn = api_client.get_transaction(::TransactionID::from_str("at1uete9wa8w993ndy6e0hsynvap0yfpzru82ps5tm3hx6g908p3upsf8kl8s").unwrap()).unwrap();//(::TransactionID::from_str(&add_minter_txn_id).unwrap()).unwrap(); - // println!("----> Minter TXN owner for checking - {:?}", add_minter_txn.owner()); - // // let record_pointer_NFT_mint = - // let mut nonce = "".to_string(); - // let mut commitment = "".to_string(); - // let mut latest_height = api_client.latest_height().unwrap(); - // for transition in add_minter_txn.clone().into_transitions(){ - // if transition.program_id().to_string() == program_id { - // let record_pointer_NFT_mint = transition_to_record_pointer(add_minter_txn.clone().id(), transition.clone(), latest_height, vk).unwrap(); - // // STEP - 4 set_mint_block() - // for record in record_pointer_NFT_mint{ - // let mint_block = format!("{}u32",record.pointer.block_height); - // let mint_block_inputs = vec![Value::::try_from(mint_block.to_string()).unwrap()]; - // // let block_txn_id = program_manager.execute_program(program_id, "set_mint_block", mint_block_inputs.iter(), fee, None, None).unwrap().to_string(); - // // println!("----> Updated block number (TXN-ID) - {:?}", block_txn_id); - - // nonce = record.metadata.nonce; - // commitment = record.pointer.commitment; - - // } - // } - // } - // // SETUP NFT_MINT RECORD - // let NFT_mint_record = format!("{}{}{}", RECORD_NFT_MINT, nonce, ".public }"); - // println!("----> NFT_mint.record created and stored - {:?}", NFT_mint_record); - // // STEP - 5 update_toggle_settings() - // let settings_inputs = vec![settings.clone()]; - // // let settings_txn_id = program_manager.execute_program(program_id, "update_toggle_settings", settings_inputs.iter(), fee, None, None).unwrap().to_string(); - // // println!("----> Updated settings to allow minting without whitelisting (TXN-ID) - {:?}", settings_txn_id); - - // // STEP - 6 open_mint() - // // let open_mint_inputs = vec![hiding_nonce.clone()]; - // // let open_mint_txn_id = program_manager.execute_program(program_id, "open_mint", open_mint_inputs.iter(), fee, None, None).unwrap().to_string(); - // // println!("----> Open Mint function invoked (TXN-ID) - {:?}", open_mint_txn_id); - // let open_mint_txn = api_client.get_transaction(::TransactionID::from_str("at1xj60pnlgzg0tc5ntm2n02vll93uq4xtretadjzea343h2qgl8gzq4m0yuk").unwrap()).unwrap(); - // let mut claim_nonce = "".to_string(); - // let mut claim = "0field"; - // let mut latest_height = api_client.latest_height().unwrap(); - // for transition in open_mint_txn.clone().into_transitions(){ - // if transition.program_id().to_string() == program_id { - // let record_pointer_NFT_claim = transition_to_record_pointer(add_minter_txn.clone().id(), transition.clone(), latest_height, vk).unwrap(); - // for record in record_pointer_NFT_claim{ - // claim_nonce = record.metadata.nonce; - // } - // let ops = &transition.outputs()[1]; - // println!("----> Claim value fetch sucessful - {:?}", ops); - // } - // } - // // SETUP NFT_CLAIM RECORD - // let NFT_claim_record = format!("{}{}{}", RECORD_NFT_CLAIM, claim_nonce, ".public }"); - // println!("----> NFT_claim.record created and stored - {:?}", NFT_claim_record); - - // // STEP - 7 mint() - // let mint_inputs = vec![Value::::Record(Record::>::from_str(&NFT_mint_record.clone()).unwrap()) ,hiding_nonce.clone()]; - // let mint_txn_id = program_manager.execute_program(program_id, "mint", mint_inputs.iter(), fee, None, None).unwrap().to_string(); - // println!("----> Mint function invoked (TXN-ID) - {:?}", mint_txn_id); - - // // STEP - 8 claim_nft() - // let nft_inputs = vec![Value::::Record(Record::>::from_str(&NFT_claim_record.clone()).unwrap()) ,token_id.clone(), edition.clone()]; - // let nft_txn_id = program_manager.execute_program(program_id, "claim_nft", nft_inputs.iter(), fee, None, None).unwrap().to_string(); - // println!("----> NFT Claimed (TXN-ID) - {:?}", nft_txn_id); - - // // // FINAL STEP - SEND THE TRANSITION TO FUNCTION TO GET RECORD TYPE - // let nft_txn = api_client.get_transaction(::TransactionID::from_str("at1ya42tgdqawkkwf5t8ezuez954j3lgpv92xqhlcc0eajfnzrwlc9qhgve9y").unwrap()).unwrap(); - // for transition in nft_txn.clone().into_transitions(){ - // if transition.program_id().to_string() == program_id { - // let record_pointer_NFT = transition_to_record_pointer(add_minter_txn.clone().id(), transition.clone(), latest_height, vk).unwrap(); - - // println!("----> NFT Fetched sucessfully - {:?}", record_pointer_NFT); - // } - // } - - // } - // // fn get_nonce(txn: Transaction, program_id: &str, api_client: AleoAPIClient, vk: ViewKey ) -> Metadata{ - // let latest_height = api_client.latest_height().unwrap(); - // for transition in txn.into_transitions(){ - // if transition.program_id().to_string() == program_id { - // println!("----> Transition Found - {:?}", transition.id()); - // let res = transition_to_record_pointer(txn.id(), transition.clone(), latest_height, vk).unwrap(); - // let metadata = for record in res.iter(){ - // return record.metadata; - // } - // } - // } - // return (); - // } -} diff --git a/backend/src/services/records.rs b/backend/src/services/records.rs deleted file mode 100644 index b8f67a43..00000000 --- a/backend/src/services/records.rs +++ /dev/null @@ -1,127 +0,0 @@ -// Multi Threaded get_records - in construction FIX: Output not matching -//gets the records form the latest aleo blocks and forms and returns a vector of our local block type -/* -fn get_nova_records(last_sync: u32) -> AvailResult<(Vec, Vec)> { - let view_key = get_view_session::()?; - - let api_client = AleoAPIClient::::local_testnet3("3030"); - let chunk_size = 49; - - let latest_height = api_client.latest_height()?; - - let total_blocks_num = latest_height.sub(last_sync); - let num_chunks = total_blocks_num / chunk_size; - - let chunk_ranges: Vec<(u32, u32)> = (0..num_chunks) - .map(|chunk_index| { - let start_block = chunk_index * chunk_size; - let end_block = (start_block + chunk_size).min(total_blocks_num); - (start_block, end_block) - }) - .collect(); - - let synced_encrypted_blocks = get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Block)? - .iter() - .map(|data| Ok(deserialize(&data.data)?)) - .collect::, AvError>>()?; - - //decrypt and form a vector of block heights - let synced_blocks = synced_encrypted_blocks - .iter() - .map(|block| Block::decrypt(block.to_owned()).unwrap()) - .map(|block| block.block_height) - .collect::>(); - - let address_x_coordinate = view_key.to_address().to_x_coordinate(); - - let sk_tag = GraphKey::try_from(view_key)?.sk_tag(); - - let mut end_height = latest_height; - let mut start_height = latest_height.sub(step_size); - - let mut tags: Vec = vec![]; - let mut new_record_blocks: Vec = vec![]; - - for _ in (last_sync..latest_height).step_by(step_size as usize) { - println!("start_height: {:?}", start_height); - println!("end_height: {:?}", end_height); - let blocks = api_client.get_blocks(start_height, end_height)?; - - let blocks = match blocks { - Ok(res) => res, - Err(_) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error getting blocks".to_string(), - "".to_string(), - )); - } - }; - - tags.append(&mut current_tags); - - //remove any blocks that are already synced - let blocks = blocks - .clone() - .into_iter() - .filter(|block| !synced_blocks.contains(&block.height())) - .collect::>>(); - - let mut optimized_blocks = blocks - .iter() - .map(|block| { - let records = block.clone().into_records(); - let height = block.height(); - - let identifiers = records - .into_iter() - .filter(|(_, record)| { - record.is_owner_with_address_x_coordinate(&view_key, &address_x_coordinate) - }) - .filter_map(|(commitment, record)| { - let record = record.decrypt(&view_key).ok()?; - let tag = Record::>::tag(sk_tag, commitment).ok()?; - let amount = record.microcredits().ok()?; - if amount == 0 { - None - } else { - Some(Identifiers::new( - commitment.to_string(), - tag.to_string(), - amount, - "unspent".to_string(), - )) - } - }) - .collect(); - - Block::new(height, identifiers) - }) - .collect::>(); - - // Search in reverse order from the latest block to the earliest block - end_height = start_height; - start_height = start_height.saturating_sub(step_size); - if start_height < last_sync { - start_height = last_sync - }; - - Ok(avail_blocks) - }) - - - let tags = tags.into_inner(); - - let tags = match tags { - Ok(res) => res, - Err(_) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Mutex error ".to_string(), - "".to_string(), - )); - } - }; - - Ok((new_record_blocks, tags)) -}*/ diff --git a/backend/src/services/wallet_connect_api.rs b/backend/src/services/wallet_connect_api.rs deleted file mode 100644 index 030f18f9..00000000 --- a/backend/src/services/wallet_connect_api.rs +++ /dev/null @@ -1,1011 +0,0 @@ -use super::{ - local_storage::{ - encrypted_data::update_encrypted_transaction_state_by_id, - persistent_storage::{get_address, get_address_string, get_network}, - session::{password::PASS, view::VIEWSESSION}, - storage_api::{ - event::{ - get_avail_event_raw, get_avail_events_raw, get_event_raw, get_events_raw, - get_succinct_avail_event_raw, get_succinct_avail_events_raw, - }, - records::{ - get_page_count_for_filter, get_record_pointers, update_record_spent_local, - update_record_spent_local_via_nonce, - }, - }, - utils::{get_private_key, sign_message}, - }, - record_handling::{ - records::find_aleo_credits_record_to_spend, - utils::{ - get_token_balance, handle_deployment_update_and_encrypted_storage, - handle_encrypted_storage_and_message, handle_transaction_update_and_encrypted_storage, - parse_inputs, - }, - }, -}; -use chrono::Local; -use std::str::FromStr; - -use crate::api::aleo_client::setup_client; -use crate::models::event::{AvailEvent, SuccinctAvailEvent}; -use crate::models::pointers::{deployment::DeploymentPointer, transaction::TransactionPointer}; -use crate::models::wallet_connect::{ - balance::{BalanceRequest, BalanceResponse}, - create_event::{CreateEventRequest, CreateEventResponse}, - decrypt::{DecryptRequest, DecryptResponse}, - get_event::{GetEventRequest, GetEventResponse, GetEventsRequest, GetEventsResponse}, - records::{GetRecordsRequest, GetRecordsResponse, RecordWithPlaintext}, - sign::{SignatureRequest, SignatureResponse}, -}; - -use snarkvm::circuit::Aleo; -use snarkvm::{ - circuit::{AleoV0, Environment}, - prelude::{Address, Ciphertext, Field, Network, Program, Record, Signature, Testnet3}, -}; - -use tauri::{Manager, Window}; - -use avail_common::{ - aleo_tools::program_manager::*, - converters::messages::{field_to_fields, utf8_string_to_bits}, - errors::{AvailError, AvailErrorType, AvailResult}, - models::{ - encrypted_data::{EventTypeCommon, TransactionState}, - network::SupportedNetworks, - }, -}; - -#[tauri::command(rename_all = "snake_case")] -pub fn get_balance(request: BalanceRequest) -> AvailResult { - let network = get_network()?; - println!( - "===> Asset ID in Request Backend {:?}", - Some(request.asset_id()) - ); - //TODO - Read ARC20 to deduce assets id something like {program_id/record_name} seems reasonable. - let asset_id = match request.asset_id() { - Some(asset_id) => asset_id, - None => "credits".to_string(), - }; - println!("===> Asset ID in Backend {:?}", asset_id); - //TODO - V2 HD wallet support - let _address = match request.address() { - Some(address) => address.to_string(), - None => get_address_string()?, - }; - - let balance = match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => get_token_balance::(&asset_id)?, - _ => get_token_balance::(&asset_id)?, //SupportedNetworks::Mainnet => get_aleo_balance::()?, - }; - - Ok(BalanceResponse::new(vec![balance], None)) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn request_create_event( - request: CreateEventRequest, - fee_private: bool, - window: Window, -) -> AvailResult { - let network = get_network()?; - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - request_create_event_raw::(request, fee_private, Some(window)).await - } - _ => request_create_event_raw::(request, fee_private, Some(window)).await, //SupportedNetworks::Mainnet => request_create_event_raw::(request), - } -} - -pub async fn request_create_event_raw>( - request: CreateEventRequest, - fee_private: bool, - window: Option, -) -> AvailResult { - let api_client = setup_client::()?; - let private_key = match get_private_key::(None) { - Ok(private_key) => { - PASS.extend_session()?; - private_key - } - Err(e) => match e.error_type { - AvailErrorType::Unauthorized => { - if let Some(window) = window { - match window.emit("reauthenticate", "create-event") { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting reauthentication event".to_string(), - "Error emitting reauthentication state".to_string(), - )); - } - }; - } - - return Ok(CreateEventResponse::new( - None, - Some("Unauthorized, please reauthenticate.".to_string()), - )); - } - _ => { - return Ok(CreateEventResponse::new( - None, - Some("Error signing the event creation.".to_string()), - )); - } - }, - }; - - let address = get_address::()?; - let fee = (request.fee() * 1000000.0) as u64; - - let mut program_manager = - ProgramManager::::new(Some(private_key), None, Some(api_client), None)?; - - let mut fee_record_nonce: Option = None; - - if request.event_type() == &EventTypeCommon::Deploy { - let program = match request.inputs().get(0) { - Some(program) => program, - None => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Program not found".to_string(), - "Program not found".to_string(), - )) - } - }; - - let program = match Program::::from_str(program) { - Ok(program) => program, - Err(_) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Program string parsing failure".to_string(), - "Program string parsing failure".to_string(), - )) - } - }; - - program_manager.add_program(&program)?; - - // TODO - Check if dapps take all costs into account for deployment - //let (minimum_deployment_cost, (_storage_cost, _namespace_cost)) = - // program_manager.estimate_deployment_fee::(&program, &private_key)?; - - //let mut fee = minimum_deployment_cost; - //fee += request.fee(); - - let (fee_record, _fee_commitment, fee_id) = match fee_private { - true => { - let (fee_record, fee_commitment, fee_id) = - find_aleo_credits_record_to_spend::(&fee, vec![])?; - - let fee_nonce = fee_record.nonce().to_string(); - fee_record_nonce = Some(fee_nonce); - - (Some(fee_record), Some(fee_commitment), Some(fee_id)) - } - false => (None, None, None), - }; - - let mut pending_deployment_tx = DeploymentPointer::::new( - None, - request.program_id().clone(), - request.fee(), - TransactionState::Processing, - None, - fee_record_nonce, - Local::now(), - None, - None, - ); - - let pending_event_id = pending_deployment_tx.encrypt_and_store(address)?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_event_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - } - - if let Some(fee_id) = fee_id.clone() { - update_record_spent_local::(&fee_id, true)?; - } - - let transaction_id = match program_manager.deploy_program(program.id(), 0, fee_record, None) - { - Ok(tx_id) => tx_id, - Err(_) => { - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, false)?; - } - - pending_deployment_tx.update_failed_deployment( - "Deployment failed, no records were spent.".to_string(), - ); - - let encrypted_failed_deployment = - pending_deployment_tx.to_encrypted_data(address)?; - - update_encrypted_transaction_state_by_id( - &pending_event_id, - &encrypted_failed_deployment.ciphertext, - &encrypted_failed_deployment.nonce, - TransactionState::Failed, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_event_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - } - - return Ok(CreateEventResponse::new( - Some(pending_event_id), - Some(format!("Error deploying program: '{}'", program.id())), - )); - } - }; - - handle_deployment_update_and_encrypted_storage::( - transaction_id, - &pending_event_id, - fee_id, - window, - ) - .await?; - - Ok(CreateEventResponse::new(Some(pending_event_id), None)) - } else { - let mut record_nonces: Vec = vec![]; - - let (input_values, input_nonces, recipient_address, amount) = - parse_inputs::(request.inputs().clone(), &request.function_id().clone())?; - - let (fee_record, _fee_commitment, fee_id) = match fee_private { - true => { - let (fee_record, fee_commitment, fee_id) = - find_aleo_credits_record_to_spend::(&fee, input_nonces.clone())?; - - let fee_nonce = fee_record.nonce().to_string(); - record_nonces.push(fee_nonce); - - (Some(fee_record), Some(fee_commitment), Some(fee_id)) - } - false => (None, None, None), - }; - - record_nonces.extend(input_nonces.clone()); - - let mut pending_transaction = TransactionPointer::::new( - None, - None, - TransactionState::Processing, - None, - Some(request.program_id().clone()), - Some(request.function_id().clone()), - vec![], - record_nonces, - Local::now(), - None, - None, - request.event_type().to_owned(), - amount, - Some(request.fee()), - None, - ); - - let pending_event_id = pending_transaction.encrypt_and_store(address)?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_event_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - } - - // TODO - Update fee to spent and input_nonces to spent - for nonce in input_nonces.clone() { - update_record_spent_local_via_nonce::(&nonce, true)?; - } - - if let Some(fee_id) = fee_id.clone() { - update_record_spent_local::(&fee_id, false)?; - } - println!("=====> INPUTS {:?}", input_values); - let transaction_id = match program_manager.execute_program( - request.program_id().clone(), - request.function_id().clone(), - input_values.iter(), - 0, - fee_record, - None, - ) { - Ok(tx_id) => tx_id, - Err(_) => { - if let Some(fee_id) = fee_id { - update_record_spent_local::(&fee_id, false)?; - } - - for nonce in input_nonces { - update_record_spent_local_via_nonce::(&nonce, false)?; - } - - pending_transaction.update_failed_transaction( - "Transaction execution failed, no records were spent.".to_string(), - ); - - let encrypted_failed_transaction = - pending_transaction.to_encrypted_data(address)?; - - update_encrypted_transaction_state_by_id( - &pending_event_id, - &encrypted_failed_transaction.ciphertext, - &encrypted_failed_transaction.nonce, - TransactionState::Failed, - )?; - - if let Some(window) = window.clone() { - match window.emit("tx_state_change", &pending_event_id) { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting tx_state_change event".to_string(), - "Error emitting transaction state".to_string(), - )); - } - }; - } - - return Ok(CreateEventResponse::new( - Some(pending_event_id), - Some(format!( - "Error executing program: '{}' function: '{}' ", - request.program_id(), - request.function_id() - )), - )); - } - }; - - match recipient_address { - Some(recipient_address) => { - handle_encrypted_storage_and_message::( - transaction_id, - recipient_address, - &pending_event_id, - None, - fee_id, - true, - window, - ) - .await? - } - None => { - handle_transaction_update_and_encrypted_storage::( - transaction_id, - &pending_event_id, - fee_id, - window, - ) - .await? - } - } - - Ok(CreateEventResponse::new(Some(pending_event_id), None)) - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn get_records(request: GetRecordsRequest) -> AvailResult { - let network = get_network()?; - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => match get_records_raw::(request) { - Ok((records, page_count)) => { - Ok(GetRecordsResponse::new(records, Some(page_count), None)) - } - Err(error) => Ok(GetRecordsResponse::new( - vec![], - None, - Some(error.external_msg), - )), - }, - _ => match get_records_raw::(request) { - Ok((records, page_count)) => { - Ok(GetRecordsResponse::new(records, Some(page_count), None)) - } - Err(error) => Ok(GetRecordsResponse::new( - vec![], - None, - Some(error.external_msg), - )), - }, //SupportedNetworks::Mainnet => get_records_raw::(request), - } -} - -pub fn get_records_raw( - request: GetRecordsRequest, -) -> AvailResult<(Vec, i32)> { - // TODO - return page count - - let page_count = get_page_count_for_filter(request.clone())?; - let (pointers, ids) = get_record_pointers::(request)?; - - let records_with_plaintext = pointers - .iter() - .zip(ids.iter()) - .map(|(pointer, id)| { - RecordWithPlaintext::from_record_pointer::(pointer.clone(), id.clone()) - }) - .collect::>>()?; - - Ok((records_with_plaintext, page_count)) -} - -#[tauri::command(rename_all = "snake_case")] -pub fn sign(request: SignatureRequest, window: Window) -> AvailResult { - let network = get_network()?; - - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => { - match sign_message::(&request.get_message(), None) { - Ok((signature, message_field)) => Ok(SignatureResponse::new( - Some(signature.to_string()), - Some(message_field.to_string()), - None, - )), - Err(e) => { - if e.error_type == AvailErrorType::Unauthorized { - match window.emit("reauthenticate", "sign") { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting reauthentication event".to_string(), - "Error emitting reauthentication state".to_string(), - )); - } - }; - } - Ok(SignatureResponse::new( - None, - None, - Some("Signing Failed".to_string()), - )) - } - } - } - _ => match sign_message::(&request.get_message(), None) { - Ok((signature, message_field)) => Ok(SignatureResponse::new( - Some(signature.to_string()), - Some(message_field.to_string()), - None, - )), - Err(e) => { - if e.error_type == AvailErrorType::Unauthorized { - match window.emit("reauthenticate", "sign") { - Ok(_) => {} - Err(e) => { - return Err(AvailError::new( - AvailErrorType::Internal, - "Error emitting reauthentication event".to_string(), - "Error emitting reauthentication state".to_string(), - )); - } - }; - } - Ok(SignatureResponse::new( - None, - None, - Some("Signing Failed".to_string()), - )) - } - }, - //SupportedNetworks::Mainnet => decrypt_record_raw::(ciphertext), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub fn verify(message: &str, address: &str, signature: &str) -> AvailResult { - let network = get_network()?; - - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => verify_signature::(message, address, signature), - _ => verify_signature::(message, address, signature), - } -} - -fn verify_signature( - message: &str, - address: &str, - signature: &str, -) -> AvailResult { - let signature = Signature::::from_str(signature)?; - let address = Address::::from_str(address)?; - - let msg_bits = utf8_string_to_bits(message); - let msg_field = N::hash_bhp512(&msg_bits)?; - let msg = field_to_fields(&msg_field)?; - - let result = signature.verify(&address, &msg); - - Ok(result) -} - -#[tauri::command(rename_all = "snake_case")] -pub fn decrypt_records(request: DecryptRequest) -> AvailResult { - let network = get_network()?; - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => match decrypt_records_raw::(request.ciphertexts) { - Ok(plaintexts) => Ok(DecryptResponse::new(plaintexts, None)), - Err(error) => Ok(DecryptResponse::new(vec![], Some(error.external_msg))), - }, - _ => match decrypt_records_raw::(request.ciphertexts) { - Ok(plaintexts) => Ok(DecryptResponse::new(plaintexts, None)), - Err(error) => Ok(DecryptResponse::new(vec![], Some(error.external_msg))), - }, //SupportedNetworks::Mainnet => decrypt_record_raw::(ciphertext), - } -} - -pub fn decrypt_records_raw(ciphertext: Vec) -> AvailResult> { - let view_key = VIEWSESSION.get_instance::()?; - let records = ciphertext - .iter() - .map(|ciphertext| { - let record_ciphertext = Record::>::from_str(ciphertext)?; - let record = match record_ciphertext.decrypt(&view_key) { - Ok(record) => record, - Err(_) => { - return Err(AvailError::new( - AvailErrorType::SnarkVm, - format!("Decryption Failed on record: {}", ciphertext), - format!("Decryption Failed on record: {}", ciphertext), - )) - } - }; - Ok(record.to_string()) - }) - .collect::>>()?; - - Ok(records) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn get_events(request: GetEventsRequest) -> AvailResult { - let network = get_network()?; - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => match get_events_raw::(request) { - Ok(events) => Ok(GetEventsResponse::new(events, None, None)), - Err(error) => Ok(GetEventsResponse::new( - vec![], - None, - Some(error.external_msg), - )), - }, - _ => match get_events_raw::(request) { - Ok(events) => Ok(GetEventsResponse::new(events, None, None)), - Err(error) => Ok(GetEventsResponse::new( - vec![], - None, - Some(error.external_msg), - )), - }, - //SupportedNetworks::Mainnet => get_events_raw::(request), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_event(request: GetEventRequest) -> AvailResult { - let network = get_network()?; - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => match get_event_raw::(&request.id) { - Ok(event) => Ok(GetEventResponse::new(Some(event), None)), - Err(error) => Ok(GetEventResponse::new(None, Some(error.external_msg))), - }, - _ => match get_event_raw::(&request.id) { - Ok(event) => Ok(GetEventResponse::new(Some(event), None)), - Err(error) => Ok(GetEventResponse::new(None, Some(error.external_msg))), - }, - //SupportedNetworks::Mainnet => get_event_raw::(request), - } -} - -/* --Avail Events-- */ -#[tauri::command(rename_all = "snake_case")] -pub fn get_avail_events(request: GetEventsRequest) -> AvailResult> { - let network = get_network()?; - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => get_avail_events_raw::(request), - _ => get_avail_events_raw::(request), //SupportedNetworks::Mainnet => get_events_raw::(request), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_succinct_avail_events( - request: GetEventsRequest, -) -> AvailResult> { - let network = get_network()?; - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => get_succinct_avail_events_raw::(request), - _ => get_succinct_avail_events_raw::(request), - } - //SupportedNetworks::Mainnet => get_events_raw::(request), -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_succinct_avail_event(id: &str) -> AvailResult { - let network = get_network()?; - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => get_succinct_avail_event_raw::(id), - _ => get_succinct_avail_event_raw::(id), - } - //SupportedNetworks::Mainnet => get_event_raw::(request), -} - -#[tauri::command(rename_all = "snake_case")] -pub fn get_avail_event(id: &str) -> AvailResult { - let network = get_network()?; - match SupportedNetworks::from_str(&network)? { - SupportedNetworks::Testnet3 => get_avail_event_raw::(id), - _ => get_avail_event_raw::(id), //SupportedNetworks::Mainnet => get_event_raw::(request), - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::api::encrypted_data::delete_all_server_storage; - - use crate::models::storage::languages::Languages; - use crate::models::{ - transfer::TransferRequest, - wallet_connect::records::{RecordFilterType, RecordsFilter}, - }; - - use crate::services::account::key_management::key_controller::KeyController; - - #[cfg(target_os = "linux")] - use crate::services::account::key_management::key_controller::linuxKeyController; - #[cfg(target_os = "macos")] - use crate::services::account::key_management::key_controller::macKeyController; - #[cfg(target_os = "windows")] - use crate::services::account::key_management::key_controller::windowsKeyController; - - use crate::services::local_storage::encrypted_data::{ - get_encrypted_data_by_flavour, initialize_encrypted_data_table, - }; - use crate::services::local_storage::persistent_storage::initial_user_preferences; - use crate::services::local_storage::utils::sign_message_w_key; - use crate::services::local_storage::{ - encrypted_data::drop_encrypted_data_table, persistent_storage::delete_user_preferences, - }; - use crate::services::record_handling::transfer::transfer_raw; - - use avail_common::models::encrypted_data::EncryptedDataTypeCommon; - use avail_common::{models::constants::*, models::encrypted_data::EventTypeCommon}; - use snarkvm::prelude::{Address, FromStr, Identifier, PrivateKey, Testnet3, ViewKey}; - - use crate::services::account::generation::import_wallet; - - /* - #[tokio::test] - async fn test_setup_prerequisites() { - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - - drop_encrypted_data_table().unwrap(); - delete_user_preferences().unwrap(); - // initialize the user preferences - - import_wallet( - Some("Satoshi".to_string()), - STRONG_PASSWORD.to_string(), - false, - &pk.to_string(), - false, - Languages::English, - ) - .await - .unwrap(); - - let address = get_address::().unwrap(); - - let request = TransferRequest::new( - address.to_string(), - 10000000, - Some("Private Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::Private, - false, - 300000, - "credits".to_string(), - ); - - transfer_raw::(request, None).await.unwrap(); - } - */ - - fn test_setup_prerequisites() -> PrivateKey { - // no records transferred as set up. - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let view_key = ViewKey::::try_from(&pk).unwrap(); - - drop_encrypted_data_table().unwrap(); - - delete_user_preferences().unwrap(); - // initialize the user preferences - initial_user_preferences( - false, - None, - None, - false, - false, - view_key.to_address().to_string(), - Languages::English, - ) - .unwrap(); - - initialize_encrypted_data_table().unwrap(); - - VIEWSESSION.set_view_session(&view_key.to_string()).unwrap(); - - return pk; - } - - #[test] - fn test_get_balance() { - //change to what os you are testing on - //test_setup_prerequisites_mac(); - VIEWSESSION - .set_view_session("AViewKey1pViDeDV8dT1yTCdzU6ojxh8GdFDadSasRpk6mZdyz8mh") - .unwrap(); - - println!( - " <<<<<<<<<<<<<< Testing get_balance() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>" - ); - let request = BalanceRequest::new(Some("credits"), None); - let res = get_balance(request).unwrap(); - println!("res: {:?}", res); - } - - #[test] - fn test_get_records() { - test_setup_prerequisites(); - - println!( - " <<<<<<<<<<<<<< Testing get_records() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>" - ); - let records_filter = RecordsFilter::new( - vec!["credits.aleo".to_string()], - None, - RecordFilterType::All, - Some("credits.record".to_string()), - ); - - let request = GetRecordsRequest::new(None, Some(records_filter), None); - let (res, _page_count) = get_records_raw::(request).unwrap(); - // println!("res: {:?}", res); - - println!("page_count: {:?}", _page_count); - - for value in res.into_iter() { - println!("res: {:?}", value); - } - } - - #[tokio::test] - async fn test_request_create_event() { - println!(" <<<<<<<<<<<<<<< Testing request_create_event() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>"); - /* -- Has to be called here cause has to await-- */ - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - let ext = Identifier::::from_str("test").unwrap(); - - let key_controller = { - #[cfg(target_os = "linux")] - { - linuxKeyController {} - } - - #[cfg(target_os = "macos")] - { - macKeyController {} - } - - #[cfg(target_os = "windows")] - { - windowsKeyController {} - } - }; - - key_controller - .delete_key(Some(STRONG_PASSWORD), ext) - .unwrap(); - - delete_all_server_storage().await.unwrap(); - drop_encrypted_data_table().unwrap(); - - delete_user_preferences().unwrap(); - // initialize the user preferences - - import_wallet( - Some("Satoshi".to_string()), - STRONG_PASSWORD.to_string(), - false, - &pk.to_string(), - false, - Languages::English, - ) - .await - .unwrap(); - - let address = get_address::().unwrap(); - - let request = TransferRequest::new( - address.to_string(), - 10000000, - Some("Private Transfer Test".to_string()), - Some(STRONG_PASSWORD.to_string()), - TransferType::Private, - false, - 300000, - "credits".to_string(), - ); - - transfer_raw::(request, None).await.unwrap(); - /* --SETUP COMPLETE */ - - let recipient = Address::::from_str(TESTNET3_ADDRESS).unwrap(); - let (record, _, _) = find_aleo_credits_record_to_spend::(&10000, vec![]).unwrap(); - - let program_id: &str = "credits.aleo"; - let function_id: &str = "transfer_private"; - let fee = 300000u64; - let inputs: Vec = [ - record.to_string(), - recipient.to_string(), - "10000u64".to_string(), - ] - .to_vec(); - - let request = CreateEventRequest::new( - None, - EventTypeCommon::Execute, - program_id.to_string(), - function_id.to_string(), - fee as f64 / 1000000.0, - inputs, - ); - - PASS.set_pass_session(STRONG_PASSWORD).unwrap(); - - let result_create_event = - request_create_event_raw::(request, false, None) - .await - .unwrap(); - println!("res: {:?}", result_create_event); - } - - #[test] - fn test_decrypt() { - println!( - " <<<<<<<<<<<<<<< Testing decrypt() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>" - ); - - test_setup_prerequisites(); - - let records_filter = RecordsFilter::new( - vec!["credits.aleo".to_string()], - None, - RecordFilterType::Unspent, - Some("credits.record".to_string()), - ); - - let request = GetRecordsRequest::new(None, Some(records_filter), None); - let (res, _page_count) = get_records_raw::(request).unwrap(); - - let mut ciphertexts: Vec = vec![]; - - for value in res.into_iter() { - ciphertexts.push(value.record.ciphertext); - } - - let request = DecryptRequest::new(ciphertexts); - let res = decrypt_records(request).unwrap(); - - println!("Result: {:?}", res); - } - - #[tokio::test] - async fn get_events_test() { - println!( - " <<<<<<<<<<<<<<< Testing get_events() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>" - ); - - test_setup_prerequisites(); - - VIEWSESSION - .set_view_session("AViewKey1pViDeDV8dT1yTCdzU6ojxh8GdFDadSasRpk6mZdyz8mh") - .unwrap(); - - let request = GetEventsRequest { - filter: None, - page: None, - }; - - let res = get_events(request).await.unwrap(); - - println!("Result: {:?}", res); - } - - #[test] - fn get_event_test() { - println!( - " <<<<<<<<<<<<<<< Testing get_event() fn in Wallet Connect Rust API >>>>>>>>>>>>>>>" - ); - - test_setup_prerequisites(); - - let encrypted_transaction = - get_encrypted_data_by_flavour(EncryptedDataTypeCommon::Transaction).unwrap(); - - let request = GetEventRequest { - id: encrypted_transaction[0].id.unwrap().to_string(), - address: None, - }; - - let res = get_event(request).unwrap(); - - println!("Result: {:?}", res); - } - - #[test] - fn test_verify_signature() { - let pk = PrivateKey::::from_str(TESTNET_PRIVATE_KEY).unwrap(); - - let message = "Hello World"; - - let (signature, _) = sign_message_w_key::(message, &pk).unwrap(); - - let address = Address::::try_from(&pk).unwrap(); - - let res = verify(message, &address.to_string(), &signature.to_string()).unwrap(); - - assert_eq!(res, true); - } - - #[test] - fn test_fee_f64() { - let fee = 0.3; - let fee = (fee * 1000000.0) as u64; - println!("fee: {:?}", fee); - - let fee_x = 300000u64; - //divide fee_x in a way that it becomes 0.3 - let fee_x = (fee_x as f64) / 1000000.0; - println!("fee_x: {:?}", fee_x); - } -} diff --git a/backend/tauri.conf.json b/backend/tauri.conf.json deleted file mode 100644 index ff99a62f..00000000 --- a/backend/tauri.conf.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "productName": "Avail", - "identifier": "com.avail.wallet", - "build": { - "beforeDevCommand": "cd frontend ; npm i; npm run dev", - "beforeBuildCommand": "cd frontend ; npm i; npm run build", - "devUrl": "http://localhost:1420", - "frontendDist": "../frontend/dist" - }, - "bundle": { - "active": true, - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "targets": "all" - }, - "plugins": { - "updater": { - "endpoints": [ - "https://api.avail.global/release/latest" - ], - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDRDM0Y4QzExNTM2REEyQUMKUldTc29tMVRFWXcvVEQ0MDRqdHVKZjU4MkxjUUtRM3JvZTc0eE1ZZGI2YmZrRWVFQVlKTk1MZFMK" - }, - "deep-link": { - "domains": [ - { - "host": "com.avail.wallet", - "pathPrefix": [ - "avail://" - ] - } - ] - } - }, - "app": { - "security": { - "csp": null - }, - "withGlobalTauri": true, - "windows": [ - { - "fullscreen": false, - "resizable": true, - "title": "Avail", - "width": 1125, - "height": 800, - "minWidth": 843.75, - "minHeight": 600 - } - ] - } -} \ No newline at end of file diff --git a/backend/tauri.windows.conf.json b/backend/tauri.windows.conf.json deleted file mode 100644 index e18a62d7..00000000 --- a/backend/tauri.windows.conf.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "build": { - "beforeDevCommand": "cd .\\frontend\\ & npm i & npm run dev", - "beforeBuildCommand": "cd .\\frontend\\ & npm i & npm run build", - "frontendDist": "..\\frontend\\dist" - } -} \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore deleted file mode 100644 index f1752b82..00000000 --- a/frontend/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -node_modules/** -dist/** -build/** -.cargo/config.toml - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? -.vscode/* diff --git a/frontend/package-lock.json b/frontend/package-lock.json deleted file mode 100644 index 15c4ccf9..00000000 --- a/frontend/package-lock.json +++ /dev/null @@ -1,6446 +0,0 @@ -{ - "name": "avail", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "avail", - "version": "0.0.1", - "dependencies": { - "@emotion/react": "^11.11.1", - "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.3", - "@mui/material": "^5.14.3", - "@mui/x-date-pickers": "^6.18.1", - "@walletconnect/web3wallet": "^1.10.1", - "axios": "^1.5.1", - "conf": "^12.0.0", - "date-fns": "^3.2.0", - "dayjs": "^1.11.10", - "eventemitter3": "^5.0.1", - "i18next": "^23.8.2", - "platform": "^1.3.6", - "react": "^17.0.0 || ^18.0.0", - "react-code-blocks": "^0.1.4", - "react-dom": "^17.0.0 || ^18.0.0", - "react-i18next": "^14.0.5", - "react-multi-carousel": "^2.8.4", - "react-pdf": "^7.5.1", - "react-qr-code": "^2.0.12", - "react-router-dom": "^6.14.2", - "react-spinners": "^0.13.8" - }, - "devDependencies": { - "@tauri-apps/api": "^2.0.0-beta.1", - "@tauri-apps/cli": "^2.0.0-beta.0", - "@types/conf": "^3.0.0", - "@types/i18next": "^13.0.0", - "@types/node": "^18.7.10", - "@types/platform": "^1.3.4", - "@types/react": "^18.0.15", - "@types/react-dom": "^18.0.6", - "@types/react-i18next": "^8.1.0", - "@vitejs/plugin-react": "^4.2.1", - "internal-ip": "^7.0.0", - "typescript": "^4.9.5", - "vite": "^4.2.1" - }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", - "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", - "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.7", - "@babel/parser": "^7.23.6", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", - "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", - "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", - "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", - "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", - "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", - "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@emotion/babel-plugin": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", - "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/serialize": "^1.1.2", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/cache": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", - "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", - "dependencies": { - "@emotion/memoize": "^0.8.1", - "@emotion/sheet": "^1.2.2", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/hash": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", - "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" - }, - "node_modules/@emotion/is-prop-valid": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", - "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", - "dependencies": { - "@emotion/memoize": "^0.8.1" - } - }, - "node_modules/@emotion/memoize": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" - }, - "node_modules/@emotion/react": { - "version": "11.11.3", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz", - "integrity": "sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==", - "dependencies": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.3", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", - "hoist-non-react-statics": "^3.3.1" - }, - "peerDependencies": { - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/serialize": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz", - "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==", - "dependencies": { - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/unitless": "^0.8.1", - "@emotion/utils": "^1.2.1", - "csstype": "^3.0.2" - } - }, - "node_modules/@emotion/sheet": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", - "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" - }, - "node_modules/@emotion/styled": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", - "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", - "dependencies": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/is-prop-valid": "^1.2.1", - "@emotion/serialize": "^1.1.2", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1" - }, - "peerDependencies": { - "@emotion/react": "^11.0.0-rc.0", - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" - }, - "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", - "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/@emotion/utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", - "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" - }, - "node_modules/@emotion/weak-memoize": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", - "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" - }, - "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@ethersproject/abstract-provider": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", - "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/networks": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/web": "^5.7.0" - } - }, - "node_modules/@ethersproject/abstract-signer": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", - "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0" - } - }, - "node_modules/@ethersproject/address": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", - "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/rlp": "^5.7.0" - } - }, - "node_modules/@ethersproject/base64": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", - "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0" - } - }, - "node_modules/@ethersproject/bignumber": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", - "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "bn.js": "^5.2.1" - } - }, - "node_modules/@ethersproject/bytes": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", - "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/constants": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", - "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.7.0" - } - }, - "node_modules/@ethersproject/hash": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", - "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@ethersproject/keccak256": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", - "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "js-sha3": "0.8.0" - } - }, - "node_modules/@ethersproject/logger": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", - "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ] - }, - "node_modules/@ethersproject/networks": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", - "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/properties": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", - "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/rlp": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", - "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/signing-key": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", - "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "bn.js": "^5.2.1", - "elliptic": "6.5.4", - "hash.js": "1.1.7" - } - }, - "node_modules/@ethersproject/strings": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", - "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/transactions": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", - "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0" - } - }, - "node_modules/@ethersproject/web": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", - "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@floating-ui/core": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.3.tgz", - "integrity": "sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==", - "dependencies": { - "@floating-ui/utils": "^0.2.0" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.4.tgz", - "integrity": "sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==", - "dependencies": { - "@floating-ui/core": "^1.5.3", - "@floating-ui/utils": "^0.2.0" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.5.tgz", - "integrity": "sha512-UsBK30Bg+s6+nsgblXtZmwHhgS2vmbuQK22qgt2pTQM6M3X6H1+cQcLXqgRY3ihVLcZJE6IvqDQozhsnIVqK/Q==", - "dependencies": { - "@floating-ui/dom": "^1.5.4" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", - "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" - }, - "node_modules/@ioredis/commands": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", - "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz", - "integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", - "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/@mui/base": { - "version": "5.0.0-beta.31", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.31.tgz", - "integrity": "sha512-+uNbP3OHJuZVI00WyMg7xfLZotaEY7LgvYXDfONVJbrS+K9wyjCIPNfjy8r9XJn4fbHo/5ibiZqjWnU9LMNv+A==", - "dependencies": { - "@babel/runtime": "^7.23.7", - "@floating-ui/react-dom": "^2.0.5", - "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.4", - "@popperjs/core": "^2.11.8", - "clsx": "^2.1.0", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/core-downloads-tracker": { - "version": "5.15.4", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.4.tgz", - "integrity": "sha512-0OZN9O6hAtBpx70mMNFOPaAIol/ytwZYPY+z7Rf9dK3+1Xlzwvj5/IeShJKvtp76S1qJyhPuvZg0+BGqQaUnUw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - } - }, - "node_modules/@mui/icons-material": { - "version": "5.15.4", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.4.tgz", - "integrity": "sha512-q/Yk7aokN8qGMpR7bwoDpBSeaNe6Bv7vaY9yHYodP37c64TM6ime05ueb/wgksOVszrKkNXC67E/XYbRWOoUFA==", - "dependencies": { - "@babel/runtime": "^7.23.7" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@mui/material": "^5.0.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/material": { - "version": "5.15.4", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.4.tgz", - "integrity": "sha512-T/LGRAC+M0c+D3+y67eHwIN5bSje0TxbcJCWR0esNvU11T0QwrX3jedXItPNBwMupF2F5VWCDHBVLlFnN3+ABA==", - "dependencies": { - "@babel/runtime": "^7.23.7", - "@mui/base": "5.0.0-beta.31", - "@mui/core-downloads-tracker": "^5.15.4", - "@mui/system": "^5.15.4", - "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.4", - "@types/react-transition-group": "^4.4.10", - "clsx": "^2.1.0", - "csstype": "^3.1.2", - "prop-types": "^15.8.1", - "react-is": "^18.2.0", - "react-transition-group": "^4.4.5" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/private-theming": { - "version": "5.15.4", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.4.tgz", - "integrity": "sha512-9N5myIMEEQTM5WYWPGvvYADzjFo12LgJ7S+2iTZkBNOcJpUxQYM1tvYjkHCDV+t1ocMOEgjR2EfJ9Dus30dBlg==", - "dependencies": { - "@babel/runtime": "^7.23.7", - "@mui/utils": "^5.15.4", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/styled-engine": { - "version": "5.15.4", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.4.tgz", - "integrity": "sha512-vtrZUXG5XI8CNiNLcxjIirW4dEbOloR+ikfm6ePBo7jXpJdpXjVzBWetrfE+5eI0cHkKWlTptnJ2voKV8pBRfw==", - "dependencies": { - "@babel/runtime": "^7.23.7", - "@emotion/cache": "^11.11.0", - "csstype": "^3.1.2", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.4.1", - "@emotion/styled": "^11.3.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - } - } - }, - "node_modules/@mui/system": { - "version": "5.15.4", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.4.tgz", - "integrity": "sha512-KCwkHajGBXPs2TK1HJjIyab4NDk0cZoBDYN/TTlXVo1qBAmCjY0vjqrlsjeoG+wrwwcezXMLs/e6OGP66fPCog==", - "dependencies": { - "@babel/runtime": "^7.23.7", - "@mui/private-theming": "^5.15.4", - "@mui/styled-engine": "^5.15.4", - "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.4", - "clsx": "^2.1.0", - "csstype": "^3.1.2", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/types": { - "version": "7.2.13", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz", - "integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==", - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/utils": { - "version": "5.15.4", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.4.tgz", - "integrity": "sha512-E2wLQGBcs3VR52CpMRjk46cGscC4cbf3Q2uyHNaAeL36yTTm+aVNbtsTCazXtjOP4BDd8lu6VtlTpVC8Rtl4mg==", - "dependencies": { - "@babel/runtime": "^7.23.7", - "@types/prop-types": "^15.7.11", - "prop-types": "^15.8.1", - "react-is": "^18.2.0" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/x-date-pickers": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-6.19.0.tgz", - "integrity": "sha512-/GccT+iFJTKjI6b9b0MWojyRKnizL/VYYAfPnR1q0wSVVXjYv7a1NK0uQlan4JbnovqoQCNVeTOCy/0bUJyD2Q==", - "dependencies": { - "@babel/runtime": "^7.23.2", - "@mui/base": "^5.0.0-beta.22", - "@mui/utils": "^5.14.16", - "@types/react-transition-group": "^4.4.8", - "clsx": "^2.0.0", - "prop-types": "^15.8.1", - "react-transition-group": "^4.4.5" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui" - }, - "peerDependencies": { - "@emotion/react": "^11.9.0", - "@emotion/styled": "^11.8.1", - "@mui/material": "^5.8.6", - "@mui/system": "^5.8.0", - "date-fns": "^2.25.0 || ^3.2.0", - "date-fns-jalali": "^2.13.0-0", - "dayjs": "^1.10.7", - "luxon": "^3.0.2", - "moment": "^2.29.4", - "moment-hijri": "^2.1.2", - "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "date-fns": { - "optional": true - }, - "date-fns-jalali": { - "optional": true - }, - "dayjs": { - "optional": true - }, - "luxon": { - "optional": true - }, - "moment": { - "optional": true - }, - "moment-hijri": { - "optional": true - }, - "moment-jalaali": { - "optional": true - } - } - }, - "node_modules/@parcel/watcher": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.3.0.tgz", - "integrity": "sha512-pW7QaFiL11O0BphO+bq3MgqeX/INAk9jgBldVDYjlQPO4VddoZnF22TcF9onMhnLVHuNqBJeRf+Fj7eezi/+rQ==", - "hasInstallScript": true, - "dependencies": { - "detect-libc": "^1.0.3", - "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.3.0", - "@parcel/watcher-darwin-arm64": "2.3.0", - "@parcel/watcher-darwin-x64": "2.3.0", - "@parcel/watcher-freebsd-x64": "2.3.0", - "@parcel/watcher-linux-arm-glibc": "2.3.0", - "@parcel/watcher-linux-arm64-glibc": "2.3.0", - "@parcel/watcher-linux-arm64-musl": "2.3.0", - "@parcel/watcher-linux-x64-glibc": "2.3.0", - "@parcel/watcher-linux-x64-musl": "2.3.0", - "@parcel/watcher-win32-arm64": "2.3.0", - "@parcel/watcher-win32-ia32": "2.3.0", - "@parcel/watcher-win32-x64": "2.3.0" - } - }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.3.0.tgz", - "integrity": "sha512-f4o9eA3dgk0XRT3XhB0UWpWpLnKgrh1IwNJKJ7UJek7eTYccQ8LR7XUWFKqw6aEq5KUNlCcGvSzKqSX/vtWVVA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.3.0.tgz", - "integrity": "sha512-mKY+oijI4ahBMc/GygVGvEdOq0L4DxhYgwQqYAz/7yPzuGi79oXrZG52WdpGA1wLBPrYb0T8uBaGFo7I6rvSKw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.3.0.tgz", - "integrity": "sha512-20oBj8LcEOnLE3mgpy6zuOq8AplPu9NcSSSfyVKgfOhNAc4eF4ob3ldj0xWjGGbOF7Dcy1Tvm6ytvgdjlfUeow==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.3.0.tgz", - "integrity": "sha512-7LftKlaHunueAEiojhCn+Ef2CTXWsLgTl4hq0pkhkTBFI3ssj2bJXmH2L67mKpiAD5dz66JYk4zS66qzdnIOgw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.3.0.tgz", - "integrity": "sha512-1apPw5cD2xBv1XIHPUlq0cO6iAaEUQ3BcY0ysSyD9Kuyw4MoWm1DV+W9mneWI+1g6OeP6dhikiFE6BlU+AToTQ==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.3.0.tgz", - "integrity": "sha512-mQ0gBSQEiq1k/MMkgcSB0Ic47UORZBmWoAWlMrTW6nbAGoLZP+h7AtUM7H3oDu34TBFFvjy4JCGP43JlylkTQA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.3.0.tgz", - "integrity": "sha512-LXZAExpepJew0Gp8ZkJ+xDZaTQjLHv48h0p0Vw2VMFQ8A+RKrAvpFuPVCVwKJCr5SE+zvaG+Etg56qXvTDIedw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.3.0.tgz", - "integrity": "sha512-P7Wo91lKSeSgMTtG7CnBS6WrA5otr1K7shhSjKHNePVmfBHDoAOHYRXgUmhiNfbcGk0uMCHVcdbfxtuiZCHVow==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.3.0.tgz", - "integrity": "sha512-+kiRE1JIq8QdxzwoYY+wzBs9YbJ34guBweTK8nlzLKimn5EQ2b2FSC+tAOpq302BuIMjyuUGvBiUhEcLIGMQ5g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-wasm": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-wasm/-/watcher-wasm-2.3.0.tgz", - "integrity": "sha512-ejBAX8H0ZGsD8lSICDNyMbSEtPMWgDL0WFCt/0z7hyf5v8Imz4rAM8xY379mBsECkq/Wdqa5WEDLqtjZ+6NxfA==", - "bundleDependencies": [ - "napi-wasm" - ], - "dependencies": { - "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "napi-wasm": "^1.1.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-wasm/node_modules/napi-wasm": { - "version": "1.1.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.3.0.tgz", - "integrity": "sha512-35gXCnaz1AqIXpG42evcoP2+sNL62gZTMZne3IackM+6QlfMcJLy3DrjuL6Iks7Czpd3j4xRBzez3ADCj1l7Aw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.3.0.tgz", - "integrity": "sha512-FJS/IBQHhRpZ6PiCjFt1UAcPr0YmCLHRbTc00IBTrelEjlmmgIVLeOx4MSXzx2HFEy5Jo5YdhGpxCuqCyDJ5ow==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.3.0.tgz", - "integrity": "sha512-dLx+0XRdMnVI62kU3wbXvbIRhLck4aE28bIGKbRGS7BJNt54IIj9+c/Dkqb+7DJEbHUZAX1bwaoM8PqVlHJmCA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher/node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@remix-run/router": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.2.tgz", - "integrity": "sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@stablelib/aead": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/aead/-/aead-1.0.1.tgz", - "integrity": "sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==" - }, - "node_modules/@stablelib/binary": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", - "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", - "dependencies": { - "@stablelib/int": "^1.0.1" - } - }, - "node_modules/@stablelib/bytes": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", - "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" - }, - "node_modules/@stablelib/chacha": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/chacha/-/chacha-1.0.1.tgz", - "integrity": "sha512-Pmlrswzr0pBzDofdFuVe1q7KdsHKhhU24e8gkEwnTGOmlC7PADzLVxGdn2PoNVBBabdg0l/IfLKg6sHAbTQugg==", - "dependencies": { - "@stablelib/binary": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/chacha20poly1305": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/chacha20poly1305/-/chacha20poly1305-1.0.1.tgz", - "integrity": "sha512-MmViqnqHd1ymwjOQfghRKw2R/jMIGT3wySN7cthjXCBdO+qErNPUBnRzqNpnvIwg7JBCg3LdeCZZO4de/yEhVA==", - "dependencies": { - "@stablelib/aead": "^1.0.1", - "@stablelib/binary": "^1.0.1", - "@stablelib/chacha": "^1.0.1", - "@stablelib/constant-time": "^1.0.1", - "@stablelib/poly1305": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", - "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" - }, - "node_modules/@stablelib/ed25519": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-1.0.3.tgz", - "integrity": "sha512-puIMWaX9QlRsbhxfDc5i+mNPMY+0TmQEskunY1rZEBPi1acBCVQAhnsk/1Hk50DGPtVsZtAWQg4NHGlVaO9Hqg==", - "dependencies": { - "@stablelib/random": "^1.0.2", - "@stablelib/sha512": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/hash": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", - "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" - }, - "node_modules/@stablelib/hkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/hkdf/-/hkdf-1.0.1.tgz", - "integrity": "sha512-SBEHYE16ZXlHuaW5RcGk533YlBj4grMeg5TooN80W3NpcHRtLZLLXvKyX0qcRFxf+BGDobJLnwkvgEwHIDBR6g==", - "dependencies": { - "@stablelib/hash": "^1.0.1", - "@stablelib/hmac": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/hmac": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/hmac/-/hmac-1.0.1.tgz", - "integrity": "sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==", - "dependencies": { - "@stablelib/constant-time": "^1.0.1", - "@stablelib/hash": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/int": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", - "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" - }, - "node_modules/@stablelib/keyagreement": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", - "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", - "dependencies": { - "@stablelib/bytes": "^1.0.1" - } - }, - "node_modules/@stablelib/poly1305": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", - "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", - "dependencies": { - "@stablelib/constant-time": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/random": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", - "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", - "dependencies": { - "@stablelib/binary": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/sha256": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/sha256/-/sha256-1.0.1.tgz", - "integrity": "sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==", - "dependencies": { - "@stablelib/binary": "^1.0.1", - "@stablelib/hash": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/sha512": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/sha512/-/sha512-1.0.1.tgz", - "integrity": "sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==", - "dependencies": { - "@stablelib/binary": "^1.0.1", - "@stablelib/hash": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/wipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", - "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" - }, - "node_modules/@stablelib/x25519": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", - "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", - "dependencies": { - "@stablelib/keyagreement": "^1.0.1", - "@stablelib/random": "^1.0.2", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@tauri-apps/api": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.0.0-beta.1.tgz", - "integrity": "sha512-Zok1HA5s38E951CD2Osg7qi1/NlT7K1zOK6/nf5t/SKkoRT8KPrPZlJ4zBOImLQpHdaLtEANjcjBfYcbM2noxQ==", - "dev": true, - "engines": { - "node": ">= 18", - "npm": ">= 6.6.0", - "yarn": ">= 1.19.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/tauri" - } - }, - "node_modules/@tauri-apps/cli": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.0.0-beta.1.tgz", - "integrity": "sha512-u3AcZPdHsg9qT3e9PSD0H2IVZetQvWuBOyF81CN7/sY+AJGOli7i2d38Bj4wJs50tuMotoseiMcxuyxTlAdBnw==", - "dev": true, - "bin": { - "tauri": "tauri.js" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/tauri" - }, - "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.0.0-beta.1", - "@tauri-apps/cli-darwin-x64": "2.0.0-beta.1", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.0.0-beta.1", - "@tauri-apps/cli-linux-arm64-gnu": "2.0.0-beta.1", - "@tauri-apps/cli-linux-arm64-musl": "2.0.0-beta.1", - "@tauri-apps/cli-linux-x64-gnu": "2.0.0-beta.1", - "@tauri-apps/cli-linux-x64-musl": "2.0.0-beta.1", - "@tauri-apps/cli-win32-arm64-msvc": "2.0.0-beta.1", - "@tauri-apps/cli-win32-ia32-msvc": "2.0.0-beta.1", - "@tauri-apps/cli-win32-x64-msvc": "2.0.0-beta.1" - } - }, - "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.0.0-beta.1.tgz", - "integrity": "sha512-d71utEr9H3fXAI6nKPaPuINpnvMQn+UIscOTzTMcrmIDqptOO0ix8z6C3HSvNxV0OjtlxzNJGWwOb24U0OYrgw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.0.0-beta.1.tgz", - "integrity": "sha512-bzsWZjQt5NG1uhbDTGw8Hmvm+J1d+9J7HXMMMwQc4E3kBns95sr4bIoXvgIq3cZYS4uyZOvdhEdjkSGg1c65Lg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.0.0-beta.1.tgz", - "integrity": "sha512-FMnZpk4a5D9QgZKkT00P3f4CHEZFpn/b+pWfZJ7vxCdir+Cc1eKOHiqhvmMBEeLlYlQFBaYeAK0EaZWnN82ZJA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.0.0-beta.1.tgz", - "integrity": "sha512-0kE65P+6ppeAOFsJV6av5VhkjDv1dcHkObErpjJHpwYowuC3aqaCCnH3biR9gNvcoVUXsCwmMA/BkxUpq9W9/g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.0-beta.1.tgz", - "integrity": "sha512-Wsj1eSrrAVeuFQWJq1gVIA78I8JM50fEsxbrMAOf89ZXpCYxJTNCJkyRQyLB+yHhv9nmhA3a1Mmr5ubhRETy1Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.0.0-beta.1.tgz", - "integrity": "sha512-LkzLJWg+ud2gWuq8yAWJ3Sahrp79Vbd2Cotbm/RbfMi7RbRV8TQYj4zfUhyFJVnk4nF89kTnwfNxLdTw67CAOw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.0-beta.1.tgz", - "integrity": "sha512-Ro3PuLSNEZAw9/Rc2CP3k9P7LaUQ2TOFXJeW6G4aCXrd0MlJwlGhhjdZuLbmgzD1rda4dSpZGJPhbYvu8YD7eQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.0.0-beta.1.tgz", - "integrity": "sha512-SWNF+5B+lBbW/Kq1wTMVG9x97PqJUOo8eWAr/nlMm3J0lYbTWAa8/ScibaPjq82HiPhv8WCJXlcO6FEqWCoJ2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.0.0-beta.1.tgz", - "integrity": "sha512-NvfP16fSlfq6GLHJH+gAxEsJn+Jvz3HoxMTLxAg7Ra0ycMODFu4xbNn6Hp7Djn297qTHHLYDva4Np6Whw5DUlQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.0.0-beta.1.tgz", - "integrity": "sha512-9TKbDQyVHW0p1a7aXQEKg+MhCyFMpzD26puLKOxbTPiTcRUR4lUFq5Bhf1VR5ihoqnZNhJEtuR1mA16ZrIkuKQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", - "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/conf": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/conf/-/conf-3.0.0.tgz", - "integrity": "sha512-5uooDqTJ2tBOXK60Ie6d3fpjTb9SxRzgnCqXvZrS5L2NwVOXaovYtlz78fputwm1QqXq/SROhP1NStLferLBOg==", - "deprecated": "This is a stub types definition. conf provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "conf": "*" - } - }, - "node_modules/@types/hast": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.9.tgz", - "integrity": "sha512-pTHyNlaMD/oKJmS+ZZUyFUcsZeBZpC0lmGquw98CqRVNgAdJZJeD7GoeLiT6Xbx5rU9VCjSt0RwEvDgzh4obFw==", - "dependencies": { - "@types/unist": "^2" - } - }, - "node_modules/@types/i18next": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@types/i18next/-/i18next-13.0.0.tgz", - "integrity": "sha512-gp/SIShAuf4WOqi8ey0nuI7qfWaVpMNCcs/xLygrh/QTQIXmlDC1E0TtVejweNW+7SGDY7g0lyxyKZIJuCKIJw==", - "deprecated": "This is a stub types definition. i18next provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "i18next": "*" - } - }, - "node_modules/@types/node": { - "version": "18.19.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.6.tgz", - "integrity": "sha512-X36s5CXMrrJOs2lQCdDF68apW4Rfx9ixYMawlepwmE4Anezv/AV2LSpKD1Ub8DAc+urp5bk0BGZ6NtmBitfnsg==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" - }, - "node_modules/@types/platform": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@types/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-ZmSaqHuvzv+jC232cFoz2QqPUkaj6EvMmCrWcx3WRr7xTPVFCMUOTcOq8m2d+Zw1iKRc1kDiaA+jtNrV0hkVew==", - "dev": true - }, - "node_modules/@types/prop-types": { - "version": "15.7.11", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" - }, - "node_modules/@types/react": { - "version": "18.2.47", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.47.tgz", - "integrity": "sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.2.18", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", - "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react-i18next": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/react-i18next/-/react-i18next-8.1.0.tgz", - "integrity": "sha512-d4xhcjX5b3roNMObRNMfb1HinHQlQLPo8xlDj60dnHeeAw2bBymR2cy/l1giJpHzo/ZFgSvgVUvIWr4kCrenCg==", - "deprecated": "This is a stub types definition. react-i18next provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "react-i18next": "*" - } - }, - "node_modules/@types/react-transition-group": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", - "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" - }, - "node_modules/@types/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw==" - }, - "node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", - "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.23.5", - "@babel/plugin-transform-react-jsx-self": "^7.23.3", - "@babel/plugin-transform-react-jsx-source": "^7.23.3", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" - } - }, - "node_modules/@walletconnect/auth-client": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@walletconnect/auth-client/-/auth-client-2.1.2.tgz", - "integrity": "sha512-ubJLn+vGb8sTdBFX6xAh4kjR5idrtS3RBngQWaJJJpEPBQmxMb8pM2q0FIRs8Is4K6jKy+uEhusMV+7ZBmTzjw==", - "dependencies": { - "@ethersproject/hash": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@stablelib/random": "^1.0.2", - "@stablelib/sha256": "^1.0.1", - "@walletconnect/core": "^2.10.1", - "@walletconnect/events": "^1.0.1", - "@walletconnect/heartbeat": "^1.2.1", - "@walletconnect/jsonrpc-utils": "^1.0.8", - "@walletconnect/logger": "^2.0.1", - "@walletconnect/time": "^1.0.2", - "@walletconnect/utils": "^2.10.1", - "events": "^3.3.0", - "isomorphic-unfetch": "^3.1.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@walletconnect/core": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.11.1.tgz", - "integrity": "sha512-T57Vd7YdbHPsy3tthBuwrhaZNafN0+PqjISFRNeJy/bsKdXxpJg2hGSARuOTpCO7V6VcaatqlaSMuG3DrnG5rA==", - "dependencies": { - "@walletconnect/heartbeat": "1.2.1", - "@walletconnect/jsonrpc-provider": "1.0.13", - "@walletconnect/jsonrpc-types": "1.0.3", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/jsonrpc-ws-connection": "1.0.14", - "@walletconnect/keyvaluestorage": "^1.1.1", - "@walletconnect/logger": "^2.0.1", - "@walletconnect/relay-api": "^1.0.9", - "@walletconnect/relay-auth": "^1.0.4", - "@walletconnect/safe-json": "^1.0.2", - "@walletconnect/time": "^1.0.2", - "@walletconnect/types": "2.11.1", - "@walletconnect/utils": "2.11.1", - "events": "^3.3.0", - "isomorphic-unfetch": "3.1.0", - "lodash.isequal": "4.5.0", - "uint8arrays": "^3.1.0" - } - }, - "node_modules/@walletconnect/environment": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/environment/-/environment-1.0.1.tgz", - "integrity": "sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==", - "dependencies": { - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/events": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/events/-/events-1.0.1.tgz", - "integrity": "sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==", - "dependencies": { - "keyvaluestorage-interface": "^1.0.0", - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/heartbeat": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@walletconnect/heartbeat/-/heartbeat-1.2.1.tgz", - "integrity": "sha512-yVzws616xsDLJxuG/28FqtZ5rzrTA4gUjdEMTbWB5Y8V1XHRmqq4efAxCw5ie7WjbXFSUyBHaWlMR+2/CpQC5Q==", - "dependencies": { - "@walletconnect/events": "^1.0.1", - "@walletconnect/time": "^1.0.2", - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/jsonrpc-provider": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.13.tgz", - "integrity": "sha512-K73EpThqHnSR26gOyNEL+acEex3P7VWZe6KE12ZwKzAt2H4e5gldZHbjsu2QR9cLeJ8AXuO7kEMOIcRv1QEc7g==", - "dependencies": { - "@walletconnect/jsonrpc-utils": "^1.0.8", - "@walletconnect/safe-json": "^1.0.2", - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/jsonrpc-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.3.tgz", - "integrity": "sha512-iIQ8hboBl3o5ufmJ8cuduGad0CQm3ZlsHtujv9Eu16xq89q+BG7Nh5VLxxUgmtpnrePgFkTwXirCTkwJH1v+Yw==", - "dependencies": { - "keyvaluestorage-interface": "^1.0.0", - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/jsonrpc-utils": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz", - "integrity": "sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==", - "dependencies": { - "@walletconnect/environment": "^1.0.1", - "@walletconnect/jsonrpc-types": "^1.0.3", - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/jsonrpc-ws-connection": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.14.tgz", - "integrity": "sha512-Jsl6fC55AYcbkNVkwNM6Jo+ufsuCQRqViOQ8ZBPH9pRREHH9welbBiszuTLqEJiQcO/6XfFDl6bzCJIkrEi8XA==", - "dependencies": { - "@walletconnect/jsonrpc-utils": "^1.0.6", - "@walletconnect/safe-json": "^1.0.2", - "events": "^3.3.0", - "ws": "^7.5.1" - } - }, - "node_modules/@walletconnect/keyvaluestorage": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", - "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", - "dependencies": { - "@walletconnect/safe-json": "^1.0.1", - "idb-keyval": "^6.2.1", - "unstorage": "^1.9.0" - }, - "peerDependencies": { - "@react-native-async-storage/async-storage": "1.x" - }, - "peerDependenciesMeta": { - "@react-native-async-storage/async-storage": { - "optional": true - } - } - }, - "node_modules/@walletconnect/logger": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-2.0.1.tgz", - "integrity": "sha512-SsTKdsgWm+oDTBeNE/zHxxr5eJfZmE9/5yp/Ku+zJtcTAjELb3DXueWkDXmE9h8uHIbJzIb5wj5lPdzyrjT6hQ==", - "dependencies": { - "pino": "7.11.0", - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/relay-api": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@walletconnect/relay-api/-/relay-api-1.0.9.tgz", - "integrity": "sha512-Q3+rylJOqRkO1D9Su0DPE3mmznbAalYapJ9qmzDgK28mYF9alcP3UwG/og5V7l7CFOqzCLi7B8BvcBUrpDj0Rg==", - "dependencies": { - "@walletconnect/jsonrpc-types": "^1.0.2", - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/relay-auth": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.0.4.tgz", - "integrity": "sha512-kKJcS6+WxYq5kshpPaxGHdwf5y98ZwbfuS4EE/NkQzqrDFm5Cj+dP8LofzWvjrrLkZq7Afy7WrQMXdLy8Sx7HQ==", - "dependencies": { - "@stablelib/ed25519": "^1.0.2", - "@stablelib/random": "^1.0.1", - "@walletconnect/safe-json": "^1.0.1", - "@walletconnect/time": "^1.0.2", - "tslib": "1.14.1", - "uint8arrays": "^3.0.0" - } - }, - "node_modules/@walletconnect/safe-json": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@walletconnect/safe-json/-/safe-json-1.0.2.tgz", - "integrity": "sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==", - "dependencies": { - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/sign-client": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.11.1.tgz", - "integrity": "sha512-s3oKSx6/F5X2WmkV1jfJImBFACf9Km5HpTb+n5q+mobJVpUQw/clvoVyIrNNppLhm1V1S/ylHXh0qCrDppDpCA==", - "dependencies": { - "@walletconnect/core": "2.11.1", - "@walletconnect/events": "^1.0.1", - "@walletconnect/heartbeat": "1.2.1", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/logger": "^2.0.1", - "@walletconnect/time": "^1.0.2", - "@walletconnect/types": "2.11.1", - "@walletconnect/utils": "2.11.1", - "events": "^3.3.0" - } - }, - "node_modules/@walletconnect/time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@walletconnect/time/-/time-1.0.2.tgz", - "integrity": "sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==", - "dependencies": { - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/types": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.11.1.tgz", - "integrity": "sha512-UbdbX+d6MOK0AXKxt5imV3KvAcLVpZUHylaRDIP5ffwVylM/p4DHnKppil1Qq5N+IGDr3RsUwLGFkKjqsQYRKw==", - "dependencies": { - "@walletconnect/events": "^1.0.1", - "@walletconnect/heartbeat": "1.2.1", - "@walletconnect/jsonrpc-types": "1.0.3", - "@walletconnect/keyvaluestorage": "^1.1.1", - "@walletconnect/logger": "^2.0.1", - "events": "^3.3.0" - } - }, - "node_modules/@walletconnect/utils": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.11.1.tgz", - "integrity": "sha512-wRFDHN86dZ05mCET1H3912odIeQa8j7cZKxl1FlWRpV2YsILj9HCYSX6Uq2brwO02Kv2vryke44G1r8XI/LViA==", - "dependencies": { - "@stablelib/chacha20poly1305": "1.0.1", - "@stablelib/hkdf": "1.0.1", - "@stablelib/random": "^1.0.2", - "@stablelib/sha256": "1.0.1", - "@stablelib/x25519": "^1.0.3", - "@walletconnect/relay-api": "^1.0.9", - "@walletconnect/safe-json": "^1.0.2", - "@walletconnect/time": "^1.0.2", - "@walletconnect/types": "2.11.1", - "@walletconnect/window-getters": "^1.0.1", - "@walletconnect/window-metadata": "^1.0.1", - "detect-browser": "5.3.0", - "query-string": "7.1.3", - "uint8arrays": "^3.1.0" - } - }, - "node_modules/@walletconnect/web3wallet": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@walletconnect/web3wallet/-/web3wallet-1.10.1.tgz", - "integrity": "sha512-lXyfljLLQ/76F5ftgaKaIoPfj/R2Mi2Tv2JnIXNonlIlAITdghYVby+xYbh4b+0yldf8fr8lqxFuHBuVoWhMjw==", - "dependencies": { - "@walletconnect/auth-client": "2.1.2", - "@walletconnect/core": "2.11.1", - "@walletconnect/jsonrpc-provider": "1.0.13", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/logger": "2.0.1", - "@walletconnect/sign-client": "2.11.1", - "@walletconnect/types": "2.11.1", - "@walletconnect/utils": "2.11.1" - } - }, - "node_modules/@walletconnect/window-getters": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/window-getters/-/window-getters-1.0.1.tgz", - "integrity": "sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==", - "dependencies": { - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/window-metadata": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz", - "integrity": "sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==", - "dependencies": { - "@walletconnect/window-getters": "^1.0.1", - "tslib": "1.14.1" - } - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "optional": true - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "optional": true - }, - "node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "optional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/atomically": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/atomically/-/atomically-2.0.2.tgz", - "integrity": "sha512-Xfmb4q5QV7uqTlVdMSTtO5eF4DCHfNOdaPyKlbFShkzeNP+3lj3yjjcbdjSmEY4+pDBKJ9g26aP+ImTe88UHoQ==", - "dependencies": { - "stubborn-fs": "^1.2.5", - "when-exit": "^2.0.0" - } - }, - "node_modules/axios": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", - "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", - "dependencies": { - "follow-redirects": "^1.15.4", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "optional": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" - }, - "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelize": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", - "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001576", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz", - "integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/canvas": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", - "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.0", - "nan": "^2.17.0", - "simple-get": "^3.0.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "optional": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/citty": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.5.tgz", - "integrity": "sha512-AS7n5NSc0OQVMV9v6wt3ByujNIrne0/cTjiC2MYqhvao57VNfiuVksTSr2p17nVOhEr2KtqiAkGwHcgMC/qUuQ==", - "dependencies": { - "consola": "^3.2.3" - } - }, - "node_modules/clipboardy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-4.0.0.tgz", - "integrity": "sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==", - "dependencies": { - "execa": "^8.0.1", - "is-wsl": "^3.1.0", - "is64bit": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clipboardy/node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/clipboardy/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clipboardy/node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/clipboardy/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clipboardy/node_modules/npm-run-path": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", - "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clipboardy/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clipboardy/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clipboardy/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/clipboardy/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clsx": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", - "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "optional": true, - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "optional": true - }, - "node_modules/conf": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/conf/-/conf-12.0.0.tgz", - "integrity": "sha512-fIWyWUXrJ45cHCIQX+Ck1hrZDIf/9DR0P0Zewn3uNht28hbt5OfGUq8rRWsxi96pZWPyBEd0eY9ama01JTaknA==", - "dependencies": { - "ajv": "^8.12.0", - "ajv-formats": "^2.1.1", - "atomically": "^2.0.2", - "debounce-fn": "^5.1.2", - "dot-prop": "^8.0.2", - "env-paths": "^3.0.0", - "json-schema-typed": "^8.0.1", - "semver": "^7.5.4", - "uint8array-extras": "^0.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/conf/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conf/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conf/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/consola": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", - "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "optional": true - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "node_modules/cookie-es": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.0.0.tgz", - "integrity": "sha512-mWYvfOLrfEc996hlKcdABeIiPHUPC6DM2QYZdGGOvhOTbA3tjm2eBwqlJpoFdjC89NI4Qt6h0Pu06Mp+1Pj5OQ==" - }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-color-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", - "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/css-to-react-native": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", - "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", - "dependencies": { - "camelize": "^1.0.0", - "css-color-keywords": "^1.0.0", - "postcss-value-parser": "^4.0.2" - } - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" - }, - "node_modules/date-fns": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.2.0.tgz", - "integrity": "sha512-E4KWKavANzeuusPi0jUjpuI22SURAznGkx7eZV+4i6x2A+IZxAMcajgkvuDAU1bg40+xuhW1zRdVIIM/4khuIg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, - "node_modules/dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" - }, - "node_modules/debounce-fn": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-5.1.2.tgz", - "integrity": "sha512-Sr4SdOZ4vw6eQDvPYNxHogvrxmCIld/VenC5JbNrFwMiwd7lY/Z18ZFfo+EWNG4DD9nFlAujWAo/wGuOPHmy5A==", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "optional": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==" - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "optional": true - }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/destr": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.2.tgz", - "integrity": "sha512-65AlobnZMiCET00KaFFjUefxDX0khFA/E4myqZ7a6Sq1yZtR8+FVIvilVX66vF2uobSumxooYZChiRPCKNqhmg==" - }, - "node_modules/detect-browser": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", - "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==" - }, - "node_modules/detect-libc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, - "node_modules/dot-prop": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-8.0.2.tgz", - "integrity": "sha512-xaBe6ZT4DHPkg0k4Ytbvn5xoxgpG0jOS1dYxSOwAHPuNLjP3/OzN0gH55SrLqpx8cBfSaVt91lXYkApjb+nYdQ==", - "dependencies": { - "type-fest": "^3.8.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "dependencies": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.630", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.630.tgz", - "integrity": "sha512-osHqhtjojpCsACVnuD11xO5g9xaCyw7Qqn/C2KParkMv42i8jrJJgx3g7mkHfpxwhy9MnOJr8+pKOdZ7qzgizg==", - "dev": true - }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "optional": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/env-paths": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", - "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-redact": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.3.0.tgz", - "integrity": "sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/fault": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", - "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", - "dependencies": { - "format": "^0.2.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/filter-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", - "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" - }, - "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "optional": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "optional": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-port-please": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.1.2.tgz", - "integrity": "sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==" - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "optional": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/h3": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/h3/-/h3-1.10.0.tgz", - "integrity": "sha512-Tw1kcIC+AeimwRmviiObaD5EB430Yt+lTgOxLJxNr96Vd/fGRu04EF7aKfOAcpwKCI+U2JlbxOLhycD86p3Ciw==", - "dependencies": { - "cookie-es": "^1.0.0", - "defu": "^6.1.3", - "destr": "^2.0.2", - "iron-webcrypto": "^1.0.0", - "radix3": "^1.1.0", - "ufo": "^1.3.2", - "uncrypto": "^0.1.3", - "unenv": "^1.8.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "optional": true - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hastscript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", - "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", - "engines": { - "node": "*" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/html-parse-stringify": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", - "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", - "dependencies": { - "void-elements": "3.1.0" - } - }, - "node_modules/http-shutdown": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/http-shutdown/-/http-shutdown-1.2.2.tgz", - "integrity": "sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "optional": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/i18next": { - "version": "23.8.2", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.8.2.tgz", - "integrity": "sha512-Z84zyEangrlERm0ZugVy4bIt485e/H8VecGUZkZWrH7BDePG6jT73QdL9EA1tRTTVVMpry/MgWIP1FjEn0DRXA==", - "funding": [ - { - "type": "individual", - "url": "https://locize.com" - }, - { - "type": "individual", - "url": "https://locize.com/i18next.html" - }, - { - "type": "individual", - "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" - } - ], - "dependencies": { - "@babel/runtime": "^7.23.2" - } - }, - "node_modules/idb-keyval": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", - "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==" - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "optional": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/internal-ip": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-7.0.0.tgz", - "integrity": "sha512-qE4TeD4brqC45Vq/+VASeMiS1KRyfBkR6HT2sh9pZVVCzSjPkaCEfKFU+dL0PRv7NHJtvoKN2r82G6wTfzorkw==", - "dev": true, - "dependencies": { - "default-gateway": "^6.0.3", - "ipaddr.js": "^2.0.1", - "is-ip": "^3.1.0", - "p-event": "^4.2.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/internal-ip?sponsor=1" - } - }, - "node_modules/ioredis": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz", - "integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==", - "dependencies": { - "@ioredis/commands": "^1.1.1", - "cluster-key-slot": "^1.1.0", - "debug": "^4.3.4", - "denque": "^2.1.0", - "lodash.defaults": "^4.2.0", - "lodash.isarguments": "^3.1.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0", - "standard-as-callback": "^2.1.0" - }, - "engines": { - "node": ">=12.22.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ioredis" - } - }, - "node_modules/ip-regex": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", - "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ipaddr.js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", - "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/iron-webcrypto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.0.0.tgz", - "integrity": "sha512-anOK1Mktt8U1Xi7fCM3RELTuYbnFikQY5VtrDj7kPgpejV7d43tWKhzgioO0zpkazLEL/j/iayRqnJhrGfqUsg==", - "funding": { - "url": "https://github.com/sponsors/brc-dd" - } - }, - "node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-ip": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz", - "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==", - "dev": true, - "dependencies": { - "ip-regex": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is64bit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is64bit/-/is64bit-2.0.0.tgz", - "integrity": "sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==", - "dependencies": { - "system-architecture": "^0.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/isomorphic-unfetch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", - "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", - "dependencies": { - "node-fetch": "^2.6.1", - "unfetch": "^4.2.0" - } - }, - "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/json-schema-typed": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.1.tgz", - "integrity": "sha512-XQmWYj2Sm4kn4WeTYvmpKEbyPsL7nBsb647c7pMe6l02/yx2+Jfc4dT6UZkEXnIUb5LhD55r2HPsJ1milQ4rDg==" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" - }, - "node_modules/keyvaluestorage-interface": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz", - "integrity": "sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==" - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/listhen": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/listhen/-/listhen-1.5.6.tgz", - "integrity": "sha512-gTpEJhT5L85L0bFgmu+Boqu5rP4DwDtEb4Exq5gdQUxWRwx4jbzdInZkmyLONo5EwIcQB0k7ZpWlpCDPdL77EQ==", - "dependencies": { - "@parcel/watcher": "^2.3.0", - "@parcel/watcher-wasm": "2.3.0", - "citty": "^0.1.5", - "clipboardy": "^4.0.0", - "consola": "^3.2.3", - "defu": "^6.1.4", - "get-port-please": "^3.1.2", - "h3": "^1.10.0", - "http-shutdown": "^1.2.2", - "jiti": "^1.21.0", - "mlly": "^1.4.2", - "node-forge": "^1.3.1", - "pathe": "^1.1.1", - "std-env": "^3.7.0", - "ufo": "^1.3.2", - "untun": "^0.1.3", - "uqr": "^0.1.2" - }, - "bin": { - "listen": "bin/listhen.mjs", - "listhen": "bin/listhen.mjs" - } - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" - }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lowlight": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", - "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", - "dependencies": { - "fault": "^1.0.0", - "highlight.js": "~10.7.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-cancellable-promise": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/make-cancellable-promise/-/make-cancellable-promise-1.3.2.tgz", - "integrity": "sha512-GCXh3bq/WuMbS+Ky4JBPW1hYTOU+znU+Q5m9Pu+pI8EoUqIHk9+tviOKC6/qhHh8C4/As3tzJ69IF32kdz85ww==", - "funding": { - "url": "https://github.com/wojtekmaj/make-cancellable-promise?sponsor=1" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "optional": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-event-props": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-1.6.2.tgz", - "integrity": "sha512-iDwf7mA03WPiR8QxvcVHmVWEPfMY1RZXerDVNCRYW7dUr2ppH3J58Rwb39/WG39yTZdRSxr3x+2v22tvI0VEvA==", - "funding": { - "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1" - } - }, - "node_modules/merge-refs": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-1.2.2.tgz", - "integrity": "sha512-RwcT7GsQR3KbuLw1rRuodq4Nt547BKEBkliZ0qqsrpyNne9bGTFtsFIsIpx82huWhcl3kOlOlH4H0xkPk/DqVw==", - "funding": { - "url": "https://github.com/wojtekmaj/merge-refs?sponsor=1" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "optional": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mlly": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.5.0.tgz", - "integrity": "sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ==", - "dependencies": { - "acorn": "^8.11.3", - "pathe": "^1.1.2", - "pkg-types": "^1.0.3", - "ufo": "^1.3.2" - } - }, - "node_modules/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/multiformats": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", - "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" - }, - "node_modules/nan": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", - "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", - "optional": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-addon-api": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz", - "integrity": "sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==" - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch-native": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.1.tgz", - "integrity": "sha512-bW9T/uJDPAJB2YNYEpWzE54U5O3MQidXsOyTfnbKYtTtFexRvGzb1waphBN4ZwP6EcIvYYEOwW0b72BpAqydTw==" - }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "optional": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "optional": true, - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ofetch": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.3.3.tgz", - "integrity": "sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg==", - "dependencies": { - "destr": "^2.0.1", - "node-fetch-native": "^1.4.0", - "ufo": "^1.3.0" - } - }, - "node_modules/on-exit-leak-free": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz", - "integrity": "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==" - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/onetime/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", - "dev": true, - "dependencies": { - "p-timeout": "^3.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "dev": true, - "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path2d-polyfill": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", - "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==" - }, - "node_modules/pdfjs-dist": { - "version": "3.11.174", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", - "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "canvas": "^2.11.2", - "path2d-polyfill": "^2.0.1" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pino": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-7.11.0.tgz", - "integrity": "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==", - "dependencies": { - "atomic-sleep": "^1.0.0", - "fast-redact": "^3.0.0", - "on-exit-leak-free": "^0.2.0", - "pino-abstract-transport": "v0.5.0", - "pino-std-serializers": "^4.0.0", - "process-warning": "^1.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.1.0", - "safe-stable-stringify": "^2.1.0", - "sonic-boom": "^2.2.1", - "thread-stream": "^0.15.1" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/pino-abstract-transport": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", - "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", - "dependencies": { - "duplexify": "^4.1.2", - "split2": "^4.0.0" - } - }, - "node_modules/pino-std-serializers": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz", - "integrity": "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==" - }, - "node_modules/pkg-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", - "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", - "dependencies": { - "jsonc-parser": "^3.2.0", - "mlly": "^1.2.0", - "pathe": "^1.1.0" - } - }, - "node_modules/platform": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" - }, - "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/process-warning": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", - "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==" - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", - "dependencies": { - "xtend": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/qr.js": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz", - "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==" - }, - "node_modules/query-string": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", - "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", - "dependencies": { - "decode-uri-component": "^0.2.2", - "filter-obj": "^1.1.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" - }, - "node_modules/radix3": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.0.tgz", - "integrity": "sha512-pNsHDxbGORSvuSScqNJ+3Km6QAVqk8CfsCBIEoDgpqLrkD2f3QM4I7d1ozJJ172OmIcoUcerZaNWqtLkRXTV3A==" - }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-code-blocks": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/react-code-blocks/-/react-code-blocks-0.1.5.tgz", - "integrity": "sha512-p57YPvry1OY0fS/oDVfK7BBgy89jHJguyyzNbjZvMUR2/90oB0iv3D6aS/PBjuQp7JyjlRoaZ/2WRxvOyyAAEw==", - "dependencies": { - "@babel/runtime": "^7.10.4", - "react-syntax-highlighter": "^15.5.0", - "styled-components": "^6.1.0", - "tslib": "^2.6.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "react": ">=16" - } - }, - "node_modules/react-code-blocks/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-i18next": { - "version": "14.0.5", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.0.5.tgz", - "integrity": "sha512-5+bQSeEtgJrMBABBL5lO7jPdSNAbeAZ+MlFWDw//7FnVacuVu3l9EeWFzBQvZsKy+cihkbThWOAThEdH8YjGEw==", - "dependencies": { - "@babel/runtime": "^7.23.9", - "html-parse-stringify": "^3.0.1" - }, - "peerDependencies": { - "i18next": ">= 23.2.3", - "react": ">= 16.8.0" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/react-multi-carousel": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/react-multi-carousel/-/react-multi-carousel-2.8.4.tgz", - "integrity": "sha512-7Is5Wr+m2ebkR+oq2Su2tjUdBwpVtB2O6Tjb74KDNfxWe/FrsTQwezTJTk/r9cKCrRp9Li308v822/5bZm7XKg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/react-pdf": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-7.7.0.tgz", - "integrity": "sha512-704ObLnRDm5lixL4e6NXNLaincBHGNLo+NGdbO3rEXE963NlNzwLxFpmKcbdXHAMQL4rYJQWb1L0w5IL6y8Osw==", - "dependencies": { - "clsx": "^2.0.0", - "dequal": "^2.0.3", - "make-cancellable-promise": "^1.3.1", - "make-event-props": "^1.6.0", - "merge-refs": "^1.2.1", - "pdfjs-dist": "3.11.174", - "prop-types": "^15.6.2", - "tiny-invariant": "^1.0.0", - "warning": "^4.0.0" - }, - "funding": { - "url": "https://github.com/wojtekmaj/react-pdf?sponsor=1" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-qr-code": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.12.tgz", - "integrity": "sha512-k+pzP5CKLEGBRwZsDPp98/CAJeXlsYRHM2iZn1Sd5Th/HnKhIZCSg27PXO58zk8z02RaEryg+60xa4vyywMJwg==", - "dependencies": { - "prop-types": "^15.8.1", - "qr.js": "0.0.0" - }, - "peerDependencies": { - "react": "^16.x || ^17.x || ^18.x", - "react-native-svg": "*" - }, - "peerDependenciesMeta": { - "react-native-svg": { - "optional": true - } - } - }, - "node_modules/react-refresh": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", - "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-router": { - "version": "6.21.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.2.tgz", - "integrity": "sha512-jJcgiwDsnaHIeC+IN7atO0XiSRCrOsQAHHbChtJxmgqG2IaYQXSnhqGb5vk2CU/wBQA12Zt+TkbuJjIn65gzbA==", - "dependencies": { - "@remix-run/router": "1.14.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.21.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.2.tgz", - "integrity": "sha512-tE13UukgUOh2/sqYr6jPzZTzmzc70aGRP4pAjG2if0IP3aUT+sBtAKUJh0qMh0zylJHGLmzS+XWVaON4UklHeg==", - "dependencies": { - "@remix-run/router": "1.14.2", - "react-router": "6.21.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/react-spinners": { - "version": "0.13.8", - "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz", - "integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==", - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-syntax-highlighter": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz", - "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "highlight.js": "^10.4.1", - "lowlight": "^1.17.0", - "prismjs": "^1.27.0", - "refractor": "^3.6.0" - }, - "peerDependencies": { - "react": ">= 0.14.0" - } - }, - "node_modules/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/real-require": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", - "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==", - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", - "engines": { - "node": ">=4" - } - }, - "node_modules/redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", - "dependencies": { - "redis-errors": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/refractor": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", - "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", - "dependencies": { - "hastscript": "^6.0.0", - "parse-entities": "^2.0.0", - "prismjs": "~1.27.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/prismjs": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", - "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "optional": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "devOptional": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "optional": true - }, - "node_modules/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "devOptional": true - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "optional": true, - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/sonic-boom": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz", - "integrity": "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==", - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/split-on-first": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/standard-as-callback": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", - "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" - }, - "node_modules/std-env": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", - "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==" - }, - "node_modules/stream-shift": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.2.tgz", - "integrity": "sha512-rV4Bovi9xx0BFzOb/X0B2GqoIjvqPCttZdu0Wgtx2Dxkj7ETyWl9gmqJ4EutWRLvtZWm8dxE+InQZX1IryZn/w==" - }, - "node_modules/strict-uri-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "optional": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "optional": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/stubborn-fs": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/stubborn-fs/-/stubborn-fs-1.2.5.tgz", - "integrity": "sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==" - }, - "node_modules/styled-components": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.8.tgz", - "integrity": "sha512-PQ6Dn+QxlWyEGCKDS71NGsXoVLKfE1c3vApkvDYS5KAK+V8fNWGhbSUEo9Gg2iaID2tjLXegEW3bZDUGpofRWw==", - "dependencies": { - "@emotion/is-prop-valid": "1.2.1", - "@emotion/unitless": "0.8.0", - "@types/stylis": "4.2.0", - "css-to-react-native": "3.2.0", - "csstype": "3.1.2", - "postcss": "8.4.31", - "shallowequal": "1.1.0", - "stylis": "4.3.1", - "tslib": "2.5.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/styled-components" - }, - "peerDependencies": { - "react": ">= 16.8.0", - "react-dom": ">= 16.8.0" - } - }, - "node_modules/styled-components/node_modules/@emotion/unitless": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" - }, - "node_modules/styled-components/node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" - }, - "node_modules/styled-components/node_modules/stylis": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", - "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" - }, - "node_modules/styled-components/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/system-architecture": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz", - "integrity": "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", - "optional": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/thread-stream": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz", - "integrity": "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==", - "dependencies": { - "real-require": "^0.1.0" - } - }, - "node_modules/tiny-invariant": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", - "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/ufo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.2.tgz", - "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==" - }, - "node_modules/uint8array-extras": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-0.3.0.tgz", - "integrity": "sha512-erJsJwQ0tKdwuqI0359U8ijkFmfiTcq25JvvzRVc1VP+2son1NJRXhxcAKJmAW3ajM8JSGAfsAXye8g4s+znxA==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/uint8arrays": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", - "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", - "dependencies": { - "multiformats": "^9.4.2" - } - }, - "node_modules/uncrypto": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", - "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==" - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/unenv": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/unenv/-/unenv-1.9.0.tgz", - "integrity": "sha512-QKnFNznRxmbOF1hDgzpqrlIf6NC5sbZ2OJ+5Wl3OX8uM+LUJXbj4TXvLJCtwbPTmbMHCLIz6JLKNinNsMShK9g==", - "dependencies": { - "consola": "^3.2.3", - "defu": "^6.1.3", - "mime": "^3.0.0", - "node-fetch-native": "^1.6.1", - "pathe": "^1.1.1" - } - }, - "node_modules/unfetch": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", - "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==" - }, - "node_modules/unstorage": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.10.1.tgz", - "integrity": "sha512-rWQvLRfZNBpF+x8D3/gda5nUCQL2PgXy2jNG4U7/Rc9BGEv9+CAJd0YyGCROUBKs9v49Hg8huw3aih5Bf5TAVw==", - "dependencies": { - "anymatch": "^3.1.3", - "chokidar": "^3.5.3", - "destr": "^2.0.2", - "h3": "^1.8.2", - "ioredis": "^5.3.2", - "listhen": "^1.5.5", - "lru-cache": "^10.0.2", - "mri": "^1.2.0", - "node-fetch-native": "^1.4.1", - "ofetch": "^1.3.3", - "ufo": "^1.3.1" - }, - "peerDependencies": { - "@azure/app-configuration": "^1.4.1", - "@azure/cosmos": "^4.0.0", - "@azure/data-tables": "^13.2.2", - "@azure/identity": "^3.3.2", - "@azure/keyvault-secrets": "^4.7.0", - "@azure/storage-blob": "^12.16.0", - "@capacitor/preferences": "^5.0.6", - "@netlify/blobs": "^6.2.0", - "@planetscale/database": "^1.11.0", - "@upstash/redis": "^1.23.4", - "@vercel/kv": "^0.2.3", - "idb-keyval": "^6.2.1" - }, - "peerDependenciesMeta": { - "@azure/app-configuration": { - "optional": true - }, - "@azure/cosmos": { - "optional": true - }, - "@azure/data-tables": { - "optional": true - }, - "@azure/identity": { - "optional": true - }, - "@azure/keyvault-secrets": { - "optional": true - }, - "@azure/storage-blob": { - "optional": true - }, - "@capacitor/preferences": { - "optional": true - }, - "@netlify/blobs": { - "optional": true - }, - "@planetscale/database": { - "optional": true - }, - "@upstash/redis": { - "optional": true - }, - "@vercel/kv": { - "optional": true - }, - "idb-keyval": { - "optional": true - } - } - }, - "node_modules/unstorage/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/untun": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/untun/-/untun-0.1.3.tgz", - "integrity": "sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==", - "dependencies": { - "citty": "^0.1.5", - "consola": "^3.2.3", - "pathe": "^1.1.1" - }, - "bin": { - "untun": "bin/untun.mjs" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uqr": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/uqr/-/uqr-0.1.2.tgz", - "integrity": "sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/vite": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", - "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", - "dev": true, - "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/void-elements": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/when-exit": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.2.tgz", - "integrity": "sha512-u9J+toaf3CCxCAzM/484qNAxQE75rFdVgiFEEV8Xps2gzYhf0tx73s1WXDQhkwV17E3MxRMz40m7Ekd2/121Lg==" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "optional": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "engines": { - "node": ">= 6" - } - } - } -} diff --git a/frontend/index.html b/index.html similarity index 100% rename from frontend/index.html rename to index.html diff --git a/package-lock.json b/package-lock.json index 8555e4a9..15c4ccf9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6446 @@ { - "name": "avail_mobile", + "name": "avail", + "version": "0.0.1", "lockfileVersion": 3, "requires": true, - "packages": {} + "packages": { + "": { + "name": "avail", + "version": "0.0.1", + "dependencies": { + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@mui/icons-material": "^5.14.3", + "@mui/material": "^5.14.3", + "@mui/x-date-pickers": "^6.18.1", + "@walletconnect/web3wallet": "^1.10.1", + "axios": "^1.5.1", + "conf": "^12.0.0", + "date-fns": "^3.2.0", + "dayjs": "^1.11.10", + "eventemitter3": "^5.0.1", + "i18next": "^23.8.2", + "platform": "^1.3.6", + "react": "^17.0.0 || ^18.0.0", + "react-code-blocks": "^0.1.4", + "react-dom": "^17.0.0 || ^18.0.0", + "react-i18next": "^14.0.5", + "react-multi-carousel": "^2.8.4", + "react-pdf": "^7.5.1", + "react-qr-code": "^2.0.12", + "react-router-dom": "^6.14.2", + "react-spinners": "^0.13.8" + }, + "devDependencies": { + "@tauri-apps/api": "^2.0.0-beta.1", + "@tauri-apps/cli": "^2.0.0-beta.0", + "@types/conf": "^3.0.0", + "@types/i18next": "^13.0.0", + "@types/node": "^18.7.10", + "@types/platform": "^1.3.4", + "@types/react": "^18.0.15", + "@types/react-dom": "^18.0.6", + "@types/react-i18next": "^8.1.0", + "@vitejs/plugin-react": "^4.2.1", + "internal-ip": "^7.0.0", + "typescript": "^4.9.5", + "vite": "^4.2.1" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", + "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", + "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", + "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz", + "integrity": "sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz", + "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/styled": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", + "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/is-prop-valid": "^1.2.1", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.3.tgz", + "integrity": "sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==", + "dependencies": { + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.4.tgz", + "integrity": "sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==", + "dependencies": { + "@floating-ui/core": "^1.5.3", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.5.tgz", + "integrity": "sha512-UsBK30Bg+s6+nsgblXtZmwHhgS2vmbuQK22qgt2pTQM6M3X6H1+cQcLXqgRY3ihVLcZJE6IvqDQozhsnIVqK/Q==", + "dependencies": { + "@floating-ui/dom": "^1.5.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, + "node_modules/@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz", + "integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.31", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.31.tgz", + "integrity": "sha512-+uNbP3OHJuZVI00WyMg7xfLZotaEY7LgvYXDfONVJbrS+K9wyjCIPNfjy8r9XJn4fbHo/5ibiZqjWnU9LMNv+A==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@floating-ui/react-dom": "^2.0.5", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.4", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.4.tgz", + "integrity": "sha512-0OZN9O6hAtBpx70mMNFOPaAIol/ytwZYPY+z7Rf9dK3+1Xlzwvj5/IeShJKvtp76S1qJyhPuvZg0+BGqQaUnUw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.4.tgz", + "integrity": "sha512-q/Yk7aokN8qGMpR7bwoDpBSeaNe6Bv7vaY9yHYodP37c64TM6ime05ueb/wgksOVszrKkNXC67E/XYbRWOoUFA==", + "dependencies": { + "@babel/runtime": "^7.23.7" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.4.tgz", + "integrity": "sha512-T/LGRAC+M0c+D3+y67eHwIN5bSje0TxbcJCWR0esNvU11T0QwrX3jedXItPNBwMupF2F5VWCDHBVLlFnN3+ABA==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@mui/base": "5.0.0-beta.31", + "@mui/core-downloads-tracker": "^5.15.4", + "@mui/system": "^5.15.4", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.4", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.1.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.4.tgz", + "integrity": "sha512-9N5myIMEEQTM5WYWPGvvYADzjFo12LgJ7S+2iTZkBNOcJpUxQYM1tvYjkHCDV+t1ocMOEgjR2EfJ9Dus30dBlg==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@mui/utils": "^5.15.4", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.4.tgz", + "integrity": "sha512-vtrZUXG5XI8CNiNLcxjIirW4dEbOloR+ikfm6ePBo7jXpJdpXjVzBWetrfE+5eI0cHkKWlTptnJ2voKV8pBRfw==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.4.tgz", + "integrity": "sha512-KCwkHajGBXPs2TK1HJjIyab4NDk0cZoBDYN/TTlXVo1qBAmCjY0vjqrlsjeoG+wrwwcezXMLs/e6OGP66fPCog==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@mui/private-theming": "^5.15.4", + "@mui/styled-engine": "^5.15.4", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.4", + "clsx": "^2.1.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.13", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz", + "integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.4.tgz", + "integrity": "sha512-E2wLQGBcs3VR52CpMRjk46cGscC4cbf3Q2uyHNaAeL36yTTm+aVNbtsTCazXtjOP4BDd8lu6VtlTpVC8Rtl4mg==", + "dependencies": { + "@babel/runtime": "^7.23.7", + "@types/prop-types": "^15.7.11", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-date-pickers": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-6.19.0.tgz", + "integrity": "sha512-/GccT+iFJTKjI6b9b0MWojyRKnizL/VYYAfPnR1q0wSVVXjYv7a1NK0uQlan4JbnovqoQCNVeTOCy/0bUJyD2Q==", + "dependencies": { + "@babel/runtime": "^7.23.2", + "@mui/base": "^5.0.0-beta.22", + "@mui/utils": "^5.14.16", + "@types/react-transition-group": "^4.4.8", + "clsx": "^2.0.0", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.8.6", + "@mui/system": "^5.8.0", + "date-fns": "^2.25.0 || ^3.2.0", + "date-fns-jalali": "^2.13.0-0", + "dayjs": "^1.10.7", + "luxon": "^3.0.2", + "moment": "^2.29.4", + "moment-hijri": "^2.1.2", + "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "date-fns": { + "optional": true + }, + "date-fns-jalali": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + }, + "moment-hijri": { + "optional": true + }, + "moment-jalaali": { + "optional": true + } + } + }, + "node_modules/@parcel/watcher": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.3.0.tgz", + "integrity": "sha512-pW7QaFiL11O0BphO+bq3MgqeX/INAk9jgBldVDYjlQPO4VddoZnF22TcF9onMhnLVHuNqBJeRf+Fj7eezi/+rQ==", + "hasInstallScript": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.3.0", + "@parcel/watcher-darwin-arm64": "2.3.0", + "@parcel/watcher-darwin-x64": "2.3.0", + "@parcel/watcher-freebsd-x64": "2.3.0", + "@parcel/watcher-linux-arm-glibc": "2.3.0", + "@parcel/watcher-linux-arm64-glibc": "2.3.0", + "@parcel/watcher-linux-arm64-musl": "2.3.0", + "@parcel/watcher-linux-x64-glibc": "2.3.0", + "@parcel/watcher-linux-x64-musl": "2.3.0", + "@parcel/watcher-win32-arm64": "2.3.0", + "@parcel/watcher-win32-ia32": "2.3.0", + "@parcel/watcher-win32-x64": "2.3.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.3.0.tgz", + "integrity": "sha512-f4o9eA3dgk0XRT3XhB0UWpWpLnKgrh1IwNJKJ7UJek7eTYccQ8LR7XUWFKqw6aEq5KUNlCcGvSzKqSX/vtWVVA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.3.0.tgz", + "integrity": "sha512-mKY+oijI4ahBMc/GygVGvEdOq0L4DxhYgwQqYAz/7yPzuGi79oXrZG52WdpGA1wLBPrYb0T8uBaGFo7I6rvSKw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.3.0.tgz", + "integrity": "sha512-20oBj8LcEOnLE3mgpy6zuOq8AplPu9NcSSSfyVKgfOhNAc4eF4ob3ldj0xWjGGbOF7Dcy1Tvm6ytvgdjlfUeow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.3.0.tgz", + "integrity": "sha512-7LftKlaHunueAEiojhCn+Ef2CTXWsLgTl4hq0pkhkTBFI3ssj2bJXmH2L67mKpiAD5dz66JYk4zS66qzdnIOgw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.3.0.tgz", + "integrity": "sha512-1apPw5cD2xBv1XIHPUlq0cO6iAaEUQ3BcY0ysSyD9Kuyw4MoWm1DV+W9mneWI+1g6OeP6dhikiFE6BlU+AToTQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.3.0.tgz", + "integrity": "sha512-mQ0gBSQEiq1k/MMkgcSB0Ic47UORZBmWoAWlMrTW6nbAGoLZP+h7AtUM7H3oDu34TBFFvjy4JCGP43JlylkTQA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.3.0.tgz", + "integrity": "sha512-LXZAExpepJew0Gp8ZkJ+xDZaTQjLHv48h0p0Vw2VMFQ8A+RKrAvpFuPVCVwKJCr5SE+zvaG+Etg56qXvTDIedw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.3.0.tgz", + "integrity": "sha512-P7Wo91lKSeSgMTtG7CnBS6WrA5otr1K7shhSjKHNePVmfBHDoAOHYRXgUmhiNfbcGk0uMCHVcdbfxtuiZCHVow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.3.0.tgz", + "integrity": "sha512-+kiRE1JIq8QdxzwoYY+wzBs9YbJ34guBweTK8nlzLKimn5EQ2b2FSC+tAOpq302BuIMjyuUGvBiUhEcLIGMQ5g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-wasm": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-wasm/-/watcher-wasm-2.3.0.tgz", + "integrity": "sha512-ejBAX8H0ZGsD8lSICDNyMbSEtPMWgDL0WFCt/0z7hyf5v8Imz4rAM8xY379mBsECkq/Wdqa5WEDLqtjZ+6NxfA==", + "bundleDependencies": [ + "napi-wasm" + ], + "dependencies": { + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "napi-wasm": "^1.1.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-wasm/node_modules/napi-wasm": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.3.0.tgz", + "integrity": "sha512-35gXCnaz1AqIXpG42evcoP2+sNL62gZTMZne3IackM+6QlfMcJLy3DrjuL6Iks7Czpd3j4xRBzez3ADCj1l7Aw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.3.0.tgz", + "integrity": "sha512-FJS/IBQHhRpZ6PiCjFt1UAcPr0YmCLHRbTc00IBTrelEjlmmgIVLeOx4MSXzx2HFEy5Jo5YdhGpxCuqCyDJ5ow==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.3.0.tgz", + "integrity": "sha512-dLx+0XRdMnVI62kU3wbXvbIRhLck4aE28bIGKbRGS7BJNt54IIj9+c/Dkqb+7DJEbHUZAX1bwaoM8PqVlHJmCA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@remix-run/router": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.2.tgz", + "integrity": "sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@stablelib/aead": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/aead/-/aead-1.0.1.tgz", + "integrity": "sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==" + }, + "node_modules/@stablelib/binary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", + "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", + "dependencies": { + "@stablelib/int": "^1.0.1" + } + }, + "node_modules/@stablelib/bytes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", + "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" + }, + "node_modules/@stablelib/chacha": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/chacha/-/chacha-1.0.1.tgz", + "integrity": "sha512-Pmlrswzr0pBzDofdFuVe1q7KdsHKhhU24e8gkEwnTGOmlC7PADzLVxGdn2PoNVBBabdg0l/IfLKg6sHAbTQugg==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/chacha20poly1305": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/chacha20poly1305/-/chacha20poly1305-1.0.1.tgz", + "integrity": "sha512-MmViqnqHd1ymwjOQfghRKw2R/jMIGT3wySN7cthjXCBdO+qErNPUBnRzqNpnvIwg7JBCg3LdeCZZO4de/yEhVA==", + "dependencies": { + "@stablelib/aead": "^1.0.1", + "@stablelib/binary": "^1.0.1", + "@stablelib/chacha": "^1.0.1", + "@stablelib/constant-time": "^1.0.1", + "@stablelib/poly1305": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", + "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" + }, + "node_modules/@stablelib/ed25519": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-1.0.3.tgz", + "integrity": "sha512-puIMWaX9QlRsbhxfDc5i+mNPMY+0TmQEskunY1rZEBPi1acBCVQAhnsk/1Hk50DGPtVsZtAWQg4NHGlVaO9Hqg==", + "dependencies": { + "@stablelib/random": "^1.0.2", + "@stablelib/sha512": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/hash": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", + "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" + }, + "node_modules/@stablelib/hkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hkdf/-/hkdf-1.0.1.tgz", + "integrity": "sha512-SBEHYE16ZXlHuaW5RcGk533YlBj4grMeg5TooN80W3NpcHRtLZLLXvKyX0qcRFxf+BGDobJLnwkvgEwHIDBR6g==", + "dependencies": { + "@stablelib/hash": "^1.0.1", + "@stablelib/hmac": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/hmac": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hmac/-/hmac-1.0.1.tgz", + "integrity": "sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==", + "dependencies": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/int": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", + "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" + }, + "node_modules/@stablelib/keyagreement": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", + "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", + "dependencies": { + "@stablelib/bytes": "^1.0.1" + } + }, + "node_modules/@stablelib/poly1305": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", + "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", + "dependencies": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/random": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", + "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/sha256": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/sha256/-/sha256-1.0.1.tgz", + "integrity": "sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/sha512": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/sha512/-/sha512-1.0.1.tgz", + "integrity": "sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/wipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", + "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" + }, + "node_modules/@stablelib/x25519": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", + "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", + "dependencies": { + "@stablelib/keyagreement": "^1.0.1", + "@stablelib/random": "^1.0.2", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@tauri-apps/api": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.0.0-beta.1.tgz", + "integrity": "sha512-Zok1HA5s38E951CD2Osg7qi1/NlT7K1zOK6/nf5t/SKkoRT8KPrPZlJ4zBOImLQpHdaLtEANjcjBfYcbM2noxQ==", + "dev": true, + "engines": { + "node": ">= 18", + "npm": ">= 6.6.0", + "yarn": ">= 1.19.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.0.0-beta.1.tgz", + "integrity": "sha512-u3AcZPdHsg9qT3e9PSD0H2IVZetQvWuBOyF81CN7/sY+AJGOli7i2d38Bj4wJs50tuMotoseiMcxuyxTlAdBnw==", + "dev": true, + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.0.0-beta.1", + "@tauri-apps/cli-darwin-x64": "2.0.0-beta.1", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.0.0-beta.1", + "@tauri-apps/cli-linux-arm64-gnu": "2.0.0-beta.1", + "@tauri-apps/cli-linux-arm64-musl": "2.0.0-beta.1", + "@tauri-apps/cli-linux-x64-gnu": "2.0.0-beta.1", + "@tauri-apps/cli-linux-x64-musl": "2.0.0-beta.1", + "@tauri-apps/cli-win32-arm64-msvc": "2.0.0-beta.1", + "@tauri-apps/cli-win32-ia32-msvc": "2.0.0-beta.1", + "@tauri-apps/cli-win32-x64-msvc": "2.0.0-beta.1" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.0.0-beta.1.tgz", + "integrity": "sha512-d71utEr9H3fXAI6nKPaPuINpnvMQn+UIscOTzTMcrmIDqptOO0ix8z6C3HSvNxV0OjtlxzNJGWwOb24U0OYrgw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.0.0-beta.1.tgz", + "integrity": "sha512-bzsWZjQt5NG1uhbDTGw8Hmvm+J1d+9J7HXMMMwQc4E3kBns95sr4bIoXvgIq3cZYS4uyZOvdhEdjkSGg1c65Lg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.0.0-beta.1.tgz", + "integrity": "sha512-FMnZpk4a5D9QgZKkT00P3f4CHEZFpn/b+pWfZJ7vxCdir+Cc1eKOHiqhvmMBEeLlYlQFBaYeAK0EaZWnN82ZJA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.0.0-beta.1.tgz", + "integrity": "sha512-0kE65P+6ppeAOFsJV6av5VhkjDv1dcHkObErpjJHpwYowuC3aqaCCnH3biR9gNvcoVUXsCwmMA/BkxUpq9W9/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.0-beta.1.tgz", + "integrity": "sha512-Wsj1eSrrAVeuFQWJq1gVIA78I8JM50fEsxbrMAOf89ZXpCYxJTNCJkyRQyLB+yHhv9nmhA3a1Mmr5ubhRETy1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.0.0-beta.1.tgz", + "integrity": "sha512-LkzLJWg+ud2gWuq8yAWJ3Sahrp79Vbd2Cotbm/RbfMi7RbRV8TQYj4zfUhyFJVnk4nF89kTnwfNxLdTw67CAOw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.0-beta.1.tgz", + "integrity": "sha512-Ro3PuLSNEZAw9/Rc2CP3k9P7LaUQ2TOFXJeW6G4aCXrd0MlJwlGhhjdZuLbmgzD1rda4dSpZGJPhbYvu8YD7eQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.0.0-beta.1.tgz", + "integrity": "sha512-SWNF+5B+lBbW/Kq1wTMVG9x97PqJUOo8eWAr/nlMm3J0lYbTWAa8/ScibaPjq82HiPhv8WCJXlcO6FEqWCoJ2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.0.0-beta.1.tgz", + "integrity": "sha512-NvfP16fSlfq6GLHJH+gAxEsJn+Jvz3HoxMTLxAg7Ra0ycMODFu4xbNn6Hp7Djn297qTHHLYDva4Np6Whw5DUlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.0.0-beta.1.tgz", + "integrity": "sha512-9TKbDQyVHW0p1a7aXQEKg+MhCyFMpzD26puLKOxbTPiTcRUR4lUFq5Bhf1VR5ihoqnZNhJEtuR1mA16ZrIkuKQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/conf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/conf/-/conf-3.0.0.tgz", + "integrity": "sha512-5uooDqTJ2tBOXK60Ie6d3fpjTb9SxRzgnCqXvZrS5L2NwVOXaovYtlz78fputwm1QqXq/SROhP1NStLferLBOg==", + "deprecated": "This is a stub types definition. conf provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "conf": "*" + } + }, + "node_modules/@types/hast": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.9.tgz", + "integrity": "sha512-pTHyNlaMD/oKJmS+ZZUyFUcsZeBZpC0lmGquw98CqRVNgAdJZJeD7GoeLiT6Xbx5rU9VCjSt0RwEvDgzh4obFw==", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@types/i18next": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@types/i18next/-/i18next-13.0.0.tgz", + "integrity": "sha512-gp/SIShAuf4WOqi8ey0nuI7qfWaVpMNCcs/xLygrh/QTQIXmlDC1E0TtVejweNW+7SGDY7g0lyxyKZIJuCKIJw==", + "deprecated": "This is a stub types definition. i18next provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "i18next": "*" + } + }, + "node_modules/@types/node": { + "version": "18.19.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.6.tgz", + "integrity": "sha512-X36s5CXMrrJOs2lQCdDF68apW4Rfx9ixYMawlepwmE4Anezv/AV2LSpKD1Ub8DAc+urp5bk0BGZ6NtmBitfnsg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@types/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-ZmSaqHuvzv+jC232cFoz2QqPUkaj6EvMmCrWcx3WRr7xTPVFCMUOTcOq8m2d+Zw1iKRc1kDiaA+jtNrV0hkVew==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" + }, + "node_modules/@types/react": { + "version": "18.2.47", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.47.tgz", + "integrity": "sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.18", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", + "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-i18next": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/react-i18next/-/react-i18next-8.1.0.tgz", + "integrity": "sha512-d4xhcjX5b3roNMObRNMfb1HinHQlQLPo8xlDj60dnHeeAw2bBymR2cy/l1giJpHzo/ZFgSvgVUvIWr4kCrenCg==", + "deprecated": "This is a stub types definition. react-i18next provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "react-i18next": "*" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" + }, + "node_modules/@types/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw==" + }, + "node_modules/@types/unist": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", + "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.5", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0" + } + }, + "node_modules/@walletconnect/auth-client": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@walletconnect/auth-client/-/auth-client-2.1.2.tgz", + "integrity": "sha512-ubJLn+vGb8sTdBFX6xAh4kjR5idrtS3RBngQWaJJJpEPBQmxMb8pM2q0FIRs8Is4K6jKy+uEhusMV+7ZBmTzjw==", + "dependencies": { + "@ethersproject/hash": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@stablelib/random": "^1.0.2", + "@stablelib/sha256": "^1.0.1", + "@walletconnect/core": "^2.10.1", + "@walletconnect/events": "^1.0.1", + "@walletconnect/heartbeat": "^1.2.1", + "@walletconnect/jsonrpc-utils": "^1.0.8", + "@walletconnect/logger": "^2.0.1", + "@walletconnect/time": "^1.0.2", + "@walletconnect/utils": "^2.10.1", + "events": "^3.3.0", + "isomorphic-unfetch": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@walletconnect/core": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.11.1.tgz", + "integrity": "sha512-T57Vd7YdbHPsy3tthBuwrhaZNafN0+PqjISFRNeJy/bsKdXxpJg2hGSARuOTpCO7V6VcaatqlaSMuG3DrnG5rA==", + "dependencies": { + "@walletconnect/heartbeat": "1.2.1", + "@walletconnect/jsonrpc-provider": "1.0.13", + "@walletconnect/jsonrpc-types": "1.0.3", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/jsonrpc-ws-connection": "1.0.14", + "@walletconnect/keyvaluestorage": "^1.1.1", + "@walletconnect/logger": "^2.0.1", + "@walletconnect/relay-api": "^1.0.9", + "@walletconnect/relay-auth": "^1.0.4", + "@walletconnect/safe-json": "^1.0.2", + "@walletconnect/time": "^1.0.2", + "@walletconnect/types": "2.11.1", + "@walletconnect/utils": "2.11.1", + "events": "^3.3.0", + "isomorphic-unfetch": "3.1.0", + "lodash.isequal": "4.5.0", + "uint8arrays": "^3.1.0" + } + }, + "node_modules/@walletconnect/environment": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/environment/-/environment-1.0.1.tgz", + "integrity": "sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/events": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/events/-/events-1.0.1.tgz", + "integrity": "sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==", + "dependencies": { + "keyvaluestorage-interface": "^1.0.0", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/heartbeat": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@walletconnect/heartbeat/-/heartbeat-1.2.1.tgz", + "integrity": "sha512-yVzws616xsDLJxuG/28FqtZ5rzrTA4gUjdEMTbWB5Y8V1XHRmqq4efAxCw5ie7WjbXFSUyBHaWlMR+2/CpQC5Q==", + "dependencies": { + "@walletconnect/events": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/jsonrpc-provider": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.13.tgz", + "integrity": "sha512-K73EpThqHnSR26gOyNEL+acEex3P7VWZe6KE12ZwKzAt2H4e5gldZHbjsu2QR9cLeJ8AXuO7kEMOIcRv1QEc7g==", + "dependencies": { + "@walletconnect/jsonrpc-utils": "^1.0.8", + "@walletconnect/safe-json": "^1.0.2", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/jsonrpc-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.3.tgz", + "integrity": "sha512-iIQ8hboBl3o5ufmJ8cuduGad0CQm3ZlsHtujv9Eu16xq89q+BG7Nh5VLxxUgmtpnrePgFkTwXirCTkwJH1v+Yw==", + "dependencies": { + "keyvaluestorage-interface": "^1.0.0", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/jsonrpc-utils": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz", + "integrity": "sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==", + "dependencies": { + "@walletconnect/environment": "^1.0.1", + "@walletconnect/jsonrpc-types": "^1.0.3", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/jsonrpc-ws-connection": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.14.tgz", + "integrity": "sha512-Jsl6fC55AYcbkNVkwNM6Jo+ufsuCQRqViOQ8ZBPH9pRREHH9welbBiszuTLqEJiQcO/6XfFDl6bzCJIkrEi8XA==", + "dependencies": { + "@walletconnect/jsonrpc-utils": "^1.0.6", + "@walletconnect/safe-json": "^1.0.2", + "events": "^3.3.0", + "ws": "^7.5.1" + } + }, + "node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@walletconnect/logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-2.0.1.tgz", + "integrity": "sha512-SsTKdsgWm+oDTBeNE/zHxxr5eJfZmE9/5yp/Ku+zJtcTAjELb3DXueWkDXmE9h8uHIbJzIb5wj5lPdzyrjT6hQ==", + "dependencies": { + "pino": "7.11.0", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/relay-api": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-api/-/relay-api-1.0.9.tgz", + "integrity": "sha512-Q3+rylJOqRkO1D9Su0DPE3mmznbAalYapJ9qmzDgK28mYF9alcP3UwG/og5V7l7CFOqzCLi7B8BvcBUrpDj0Rg==", + "dependencies": { + "@walletconnect/jsonrpc-types": "^1.0.2", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/relay-auth": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.0.4.tgz", + "integrity": "sha512-kKJcS6+WxYq5kshpPaxGHdwf5y98ZwbfuS4EE/NkQzqrDFm5Cj+dP8LofzWvjrrLkZq7Afy7WrQMXdLy8Sx7HQ==", + "dependencies": { + "@stablelib/ed25519": "^1.0.2", + "@stablelib/random": "^1.0.1", + "@walletconnect/safe-json": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "tslib": "1.14.1", + "uint8arrays": "^3.0.0" + } + }, + "node_modules/@walletconnect/safe-json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/safe-json/-/safe-json-1.0.2.tgz", + "integrity": "sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/sign-client": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.11.1.tgz", + "integrity": "sha512-s3oKSx6/F5X2WmkV1jfJImBFACf9Km5HpTb+n5q+mobJVpUQw/clvoVyIrNNppLhm1V1S/ylHXh0qCrDppDpCA==", + "dependencies": { + "@walletconnect/core": "2.11.1", + "@walletconnect/events": "^1.0.1", + "@walletconnect/heartbeat": "1.2.1", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "^2.0.1", + "@walletconnect/time": "^1.0.2", + "@walletconnect/types": "2.11.1", + "@walletconnect/utils": "2.11.1", + "events": "^3.3.0" + } + }, + "node_modules/@walletconnect/time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/time/-/time-1.0.2.tgz", + "integrity": "sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/types": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.11.1.tgz", + "integrity": "sha512-UbdbX+d6MOK0AXKxt5imV3KvAcLVpZUHylaRDIP5ffwVylM/p4DHnKppil1Qq5N+IGDr3RsUwLGFkKjqsQYRKw==", + "dependencies": { + "@walletconnect/events": "^1.0.1", + "@walletconnect/heartbeat": "1.2.1", + "@walletconnect/jsonrpc-types": "1.0.3", + "@walletconnect/keyvaluestorage": "^1.1.1", + "@walletconnect/logger": "^2.0.1", + "events": "^3.3.0" + } + }, + "node_modules/@walletconnect/utils": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.11.1.tgz", + "integrity": "sha512-wRFDHN86dZ05mCET1H3912odIeQa8j7cZKxl1FlWRpV2YsILj9HCYSX6Uq2brwO02Kv2vryke44G1r8XI/LViA==", + "dependencies": { + "@stablelib/chacha20poly1305": "1.0.1", + "@stablelib/hkdf": "1.0.1", + "@stablelib/random": "^1.0.2", + "@stablelib/sha256": "1.0.1", + "@stablelib/x25519": "^1.0.3", + "@walletconnect/relay-api": "^1.0.9", + "@walletconnect/safe-json": "^1.0.2", + "@walletconnect/time": "^1.0.2", + "@walletconnect/types": "2.11.1", + "@walletconnect/window-getters": "^1.0.1", + "@walletconnect/window-metadata": "^1.0.1", + "detect-browser": "5.3.0", + "query-string": "7.1.3", + "uint8arrays": "^3.1.0" + } + }, + "node_modules/@walletconnect/web3wallet": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@walletconnect/web3wallet/-/web3wallet-1.10.1.tgz", + "integrity": "sha512-lXyfljLLQ/76F5ftgaKaIoPfj/R2Mi2Tv2JnIXNonlIlAITdghYVby+xYbh4b+0yldf8fr8lqxFuHBuVoWhMjw==", + "dependencies": { + "@walletconnect/auth-client": "2.1.2", + "@walletconnect/core": "2.11.1", + "@walletconnect/jsonrpc-provider": "1.0.13", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "2.0.1", + "@walletconnect/sign-client": "2.11.1", + "@walletconnect/types": "2.11.1", + "@walletconnect/utils": "2.11.1" + } + }, + "node_modules/@walletconnect/window-getters": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/window-getters/-/window-getters-1.0.1.tgz", + "integrity": "sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/window-metadata": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz", + "integrity": "sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==", + "dependencies": { + "@walletconnect/window-getters": "^1.0.1", + "tslib": "1.14.1" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "optional": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/atomically": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-2.0.2.tgz", + "integrity": "sha512-Xfmb4q5QV7uqTlVdMSTtO5eF4DCHfNOdaPyKlbFShkzeNP+3lj3yjjcbdjSmEY4+pDBKJ9g26aP+ImTe88UHoQ==", + "dependencies": { + "stubborn-fs": "^1.2.5", + "when-exit": "^2.0.0" + } + }, + "node_modules/axios": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", + "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "optional": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001576", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz", + "integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/citty": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.5.tgz", + "integrity": "sha512-AS7n5NSc0OQVMV9v6wt3ByujNIrne0/cTjiC2MYqhvao57VNfiuVksTSr2p17nVOhEr2KtqiAkGwHcgMC/qUuQ==", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/clipboardy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-4.0.0.tgz", + "integrity": "sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==", + "dependencies": { + "execa": "^8.0.1", + "is-wsl": "^3.1.0", + "is64bit": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/clipboardy/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/clipboardy/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy/node_modules/npm-run-path": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/clipboardy/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "optional": true + }, + "node_modules/conf": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/conf/-/conf-12.0.0.tgz", + "integrity": "sha512-fIWyWUXrJ45cHCIQX+Ck1hrZDIf/9DR0P0Zewn3uNht28hbt5OfGUq8rRWsxi96pZWPyBEd0eY9ama01JTaknA==", + "dependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", + "atomically": "^2.0.2", + "debounce-fn": "^5.1.2", + "dot-prop": "^8.0.2", + "env-paths": "^3.0.0", + "json-schema-typed": "^8.0.1", + "semver": "^7.5.4", + "uint8array-extras": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conf/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conf/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conf/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/consola": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", + "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie-es": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.0.0.tgz", + "integrity": "sha512-mWYvfOLrfEc996hlKcdABeIiPHUPC6DM2QYZdGGOvhOTbA3tjm2eBwqlJpoFdjC89NI4Qt6h0Pu06Mp+1Pj5OQ==" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/date-fns": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.2.0.tgz", + "integrity": "sha512-E4KWKavANzeuusPi0jUjpuI22SURAznGkx7eZV+4i6x2A+IZxAMcajgkvuDAU1bg40+xuhW1zRdVIIM/4khuIg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, + "node_modules/debounce-fn": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-5.1.2.tgz", + "integrity": "sha512-Sr4SdOZ4vw6eQDvPYNxHogvrxmCIld/VenC5JbNrFwMiwd7lY/Z18ZFfo+EWNG4DD9nFlAujWAo/wGuOPHmy5A==", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/destr": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.2.tgz", + "integrity": "sha512-65AlobnZMiCET00KaFFjUefxDX0khFA/E4myqZ7a6Sq1yZtR8+FVIvilVX66vF2uobSumxooYZChiRPCKNqhmg==" + }, + "node_modules/detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==" + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dot-prop": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-8.0.2.tgz", + "integrity": "sha512-xaBe6ZT4DHPkg0k4Ytbvn5xoxgpG0jOS1dYxSOwAHPuNLjP3/OzN0gH55SrLqpx8cBfSaVt91lXYkApjb+nYdQ==", + "dependencies": { + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.630", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.630.tgz", + "integrity": "sha512-osHqhtjojpCsACVnuD11xO5g9xaCyw7Qqn/C2KParkMv42i8jrJJgx3g7mkHfpxwhy9MnOJr8+pKOdZ7qzgizg==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "optional": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-redact": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.3.0.tgz", + "integrity": "sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "optional": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-port-please": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.1.2.tgz", + "integrity": "sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==" + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/h3": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.10.0.tgz", + "integrity": "sha512-Tw1kcIC+AeimwRmviiObaD5EB430Yt+lTgOxLJxNr96Vd/fGRu04EF7aKfOAcpwKCI+U2JlbxOLhycD86p3Ciw==", + "dependencies": { + "cookie-es": "^1.0.0", + "defu": "^6.1.3", + "destr": "^2.0.2", + "iron-webcrypto": "^1.0.0", + "radix3": "^1.1.0", + "ufo": "^1.3.2", + "uncrypto": "^0.1.3", + "unenv": "^1.8.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "engines": { + "node": "*" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, + "node_modules/http-shutdown": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/http-shutdown/-/http-shutdown-1.2.2.tgz", + "integrity": "sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/i18next": { + "version": "23.8.2", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.8.2.tgz", + "integrity": "sha512-Z84zyEangrlERm0ZugVy4bIt485e/H8VecGUZkZWrH7BDePG6jT73QdL9EA1tRTTVVMpry/MgWIP1FjEn0DRXA==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/idb-keyval": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", + "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "optional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/internal-ip": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-7.0.0.tgz", + "integrity": "sha512-qE4TeD4brqC45Vq/+VASeMiS1KRyfBkR6HT2sh9pZVVCzSjPkaCEfKFU+dL0PRv7NHJtvoKN2r82G6wTfzorkw==", + "dev": true, + "dependencies": { + "default-gateway": "^6.0.3", + "ipaddr.js": "^2.0.1", + "is-ip": "^3.1.0", + "p-event": "^4.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/internal-ip?sponsor=1" + } + }, + "node_modules/ioredis": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz", + "integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==", + "dependencies": { + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/ip-regex": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/iron-webcrypto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.0.0.tgz", + "integrity": "sha512-anOK1Mktt8U1Xi7fCM3RELTuYbnFikQY5VtrDj7kPgpejV7d43tWKhzgioO0zpkazLEL/j/iayRqnJhrGfqUsg==", + "funding": { + "url": "https://github.com/sponsors/brc-dd" + } + }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-ip": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz", + "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==", + "dev": true, + "dependencies": { + "ip-regex": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is64bit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is64bit/-/is64bit-2.0.0.tgz", + "integrity": "sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==", + "dependencies": { + "system-architecture": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isomorphic-unfetch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", + "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", + "dependencies": { + "node-fetch": "^2.6.1", + "unfetch": "^4.2.0" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json-schema-typed": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.1.tgz", + "integrity": "sha512-XQmWYj2Sm4kn4WeTYvmpKEbyPsL7nBsb647c7pMe6l02/yx2+Jfc4dT6UZkEXnIUb5LhD55r2HPsJ1milQ4rDg==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + }, + "node_modules/keyvaluestorage-interface": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz", + "integrity": "sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/listhen": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/listhen/-/listhen-1.5.6.tgz", + "integrity": "sha512-gTpEJhT5L85L0bFgmu+Boqu5rP4DwDtEb4Exq5gdQUxWRwx4jbzdInZkmyLONo5EwIcQB0k7ZpWlpCDPdL77EQ==", + "dependencies": { + "@parcel/watcher": "^2.3.0", + "@parcel/watcher-wasm": "2.3.0", + "citty": "^0.1.5", + "clipboardy": "^4.0.0", + "consola": "^3.2.3", + "defu": "^6.1.4", + "get-port-please": "^3.1.2", + "h3": "^1.10.0", + "http-shutdown": "^1.2.2", + "jiti": "^1.21.0", + "mlly": "^1.4.2", + "node-forge": "^1.3.1", + "pathe": "^1.1.1", + "std-env": "^3.7.0", + "ufo": "^1.3.2", + "untun": "^0.1.3", + "uqr": "^0.1.2" + }, + "bin": { + "listen": "bin/listhen.mjs", + "listhen": "bin/listhen.mjs" + } + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-cancellable-promise": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/make-cancellable-promise/-/make-cancellable-promise-1.3.2.tgz", + "integrity": "sha512-GCXh3bq/WuMbS+Ky4JBPW1hYTOU+znU+Q5m9Pu+pI8EoUqIHk9+tviOKC6/qhHh8C4/As3tzJ69IF32kdz85ww==", + "funding": { + "url": "https://github.com/wojtekmaj/make-cancellable-promise?sponsor=1" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-event-props": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-1.6.2.tgz", + "integrity": "sha512-iDwf7mA03WPiR8QxvcVHmVWEPfMY1RZXerDVNCRYW7dUr2ppH3J58Rwb39/WG39yTZdRSxr3x+2v22tvI0VEvA==", + "funding": { + "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1" + } + }, + "node_modules/merge-refs": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-1.2.2.tgz", + "integrity": "sha512-RwcT7GsQR3KbuLw1rRuodq4Nt547BKEBkliZ0qqsrpyNne9bGTFtsFIsIpx82huWhcl3kOlOlH4H0xkPk/DqVw==", + "funding": { + "url": "https://github.com/wojtekmaj/merge-refs?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mlly": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.5.0.tgz", + "integrity": "sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ==", + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.0.3", + "ufo": "^1.3.2" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" + }, + "node_modules/nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-addon-api": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz", + "integrity": "sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.1.tgz", + "integrity": "sha512-bW9T/uJDPAJB2YNYEpWzE54U5O3MQidXsOyTfnbKYtTtFexRvGzb1waphBN4ZwP6EcIvYYEOwW0b72BpAqydTw==" + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ofetch": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.3.3.tgz", + "integrity": "sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg==", + "dependencies": { + "destr": "^2.0.1", + "node-fetch-native": "^1.4.0", + "ufo": "^1.3.0" + } + }, + "node_modules/on-exit-leak-free": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz", + "integrity": "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-event": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", + "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "dev": true, + "dependencies": { + "p-timeout": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path2d-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==" + }, + "node_modules/pdfjs-dist": { + "version": "3.11.174", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", + "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "canvas": "^2.11.2", + "path2d-polyfill": "^2.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-7.11.0.tgz", + "integrity": "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.0.0", + "on-exit-leak-free": "^0.2.0", + "pino-abstract-transport": "v0.5.0", + "pino-std-serializers": "^4.0.0", + "process-warning": "^1.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.1.0", + "safe-stable-stringify": "^2.1.0", + "sonic-boom": "^2.2.1", + "thread-stream": "^0.15.1" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", + "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", + "dependencies": { + "duplexify": "^4.1.2", + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz", + "integrity": "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==" + }, + "node_modules/pkg-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", + "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "dependencies": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.2.0", + "pathe": "^1.1.0" + } + }, + "node_modules/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-warning": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", + "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qr.js": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz", + "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==" + }, + "node_modules/query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + }, + "node_modules/radix3": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.0.tgz", + "integrity": "sha512-pNsHDxbGORSvuSScqNJ+3Km6QAVqk8CfsCBIEoDgpqLrkD2f3QM4I7d1ozJJ172OmIcoUcerZaNWqtLkRXTV3A==" + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-code-blocks": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/react-code-blocks/-/react-code-blocks-0.1.5.tgz", + "integrity": "sha512-p57YPvry1OY0fS/oDVfK7BBgy89jHJguyyzNbjZvMUR2/90oB0iv3D6aS/PBjuQp7JyjlRoaZ/2WRxvOyyAAEw==", + "dependencies": { + "@babel/runtime": "^7.10.4", + "react-syntax-highlighter": "^15.5.0", + "styled-components": "^6.1.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/react-code-blocks/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-i18next": { + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.0.5.tgz", + "integrity": "sha512-5+bQSeEtgJrMBABBL5lO7jPdSNAbeAZ+MlFWDw//7FnVacuVu3l9EeWFzBQvZsKy+cihkbThWOAThEdH8YjGEw==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/react-multi-carousel": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/react-multi-carousel/-/react-multi-carousel-2.8.4.tgz", + "integrity": "sha512-7Is5Wr+m2ebkR+oq2Su2tjUdBwpVtB2O6Tjb74KDNfxWe/FrsTQwezTJTk/r9cKCrRp9Li308v822/5bZm7XKg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-pdf": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-7.7.0.tgz", + "integrity": "sha512-704ObLnRDm5lixL4e6NXNLaincBHGNLo+NGdbO3rEXE963NlNzwLxFpmKcbdXHAMQL4rYJQWb1L0w5IL6y8Osw==", + "dependencies": { + "clsx": "^2.0.0", + "dequal": "^2.0.3", + "make-cancellable-promise": "^1.3.1", + "make-event-props": "^1.6.0", + "merge-refs": "^1.2.1", + "pdfjs-dist": "3.11.174", + "prop-types": "^15.6.2", + "tiny-invariant": "^1.0.0", + "warning": "^4.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-pdf?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-qr-code": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.12.tgz", + "integrity": "sha512-k+pzP5CKLEGBRwZsDPp98/CAJeXlsYRHM2iZn1Sd5Th/HnKhIZCSg27PXO58zk8z02RaEryg+60xa4vyywMJwg==", + "dependencies": { + "prop-types": "^15.8.1", + "qr.js": "0.0.0" + }, + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x", + "react-native-svg": "*" + }, + "peerDependenciesMeta": { + "react-native-svg": { + "optional": true + } + } + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.21.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.2.tgz", + "integrity": "sha512-jJcgiwDsnaHIeC+IN7atO0XiSRCrOsQAHHbChtJxmgqG2IaYQXSnhqGb5vk2CU/wBQA12Zt+TkbuJjIn65gzbA==", + "dependencies": { + "@remix-run/router": "1.14.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.21.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.2.tgz", + "integrity": "sha512-tE13UukgUOh2/sqYr6jPzZTzmzc70aGRP4pAjG2if0IP3aUT+sBtAKUJh0qMh0zylJHGLmzS+XWVaON4UklHeg==", + "dependencies": { + "@remix-run/router": "1.14.2", + "react-router": "6.21.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-spinners": { + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz", + "integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==", + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-syntax-highlighter": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz", + "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.4.1", + "lowlight": "^1.17.0", + "prismjs": "^1.27.0", + "refractor": "^3.6.0" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/real-require": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", + "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "devOptional": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "optional": true + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "devOptional": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/sonic-boom": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz", + "integrity": "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==" + }, + "node_modules/stream-shift": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.2.tgz", + "integrity": "sha512-rV4Bovi9xx0BFzOb/X0B2GqoIjvqPCttZdu0Wgtx2Dxkj7ETyWl9gmqJ4EutWRLvtZWm8dxE+InQZX1IryZn/w==" + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/stubborn-fs": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/stubborn-fs/-/stubborn-fs-1.2.5.tgz", + "integrity": "sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==" + }, + "node_modules/styled-components": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.8.tgz", + "integrity": "sha512-PQ6Dn+QxlWyEGCKDS71NGsXoVLKfE1c3vApkvDYS5KAK+V8fNWGhbSUEo9Gg2iaID2tjLXegEW3bZDUGpofRWw==", + "dependencies": { + "@emotion/is-prop-valid": "1.2.1", + "@emotion/unitless": "0.8.0", + "@types/stylis": "4.2.0", + "css-to-react-native": "3.2.0", + "csstype": "3.1.2", + "postcss": "8.4.31", + "shallowequal": "1.1.0", + "stylis": "4.3.1", + "tslib": "2.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, + "node_modules/styled-components/node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "node_modules/styled-components/node_modules/stylis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", + "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" + }, + "node_modules/styled-components/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/system-architecture": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz", + "integrity": "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/thread-stream": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz", + "integrity": "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==", + "dependencies": { + "real-require": "^0.1.0" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", + "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ufo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.2.tgz", + "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==" + }, + "node_modules/uint8array-extras": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-0.3.0.tgz", + "integrity": "sha512-erJsJwQ0tKdwuqI0359U8ijkFmfiTcq25JvvzRVc1VP+2son1NJRXhxcAKJmAW3ajM8JSGAfsAXye8g4s+znxA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uint8arrays": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", + "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", + "dependencies": { + "multiformats": "^9.4.2" + } + }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unenv": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-1.9.0.tgz", + "integrity": "sha512-QKnFNznRxmbOF1hDgzpqrlIf6NC5sbZ2OJ+5Wl3OX8uM+LUJXbj4TXvLJCtwbPTmbMHCLIz6JLKNinNsMShK9g==", + "dependencies": { + "consola": "^3.2.3", + "defu": "^6.1.3", + "mime": "^3.0.0", + "node-fetch-native": "^1.6.1", + "pathe": "^1.1.1" + } + }, + "node_modules/unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==" + }, + "node_modules/unstorage": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.10.1.tgz", + "integrity": "sha512-rWQvLRfZNBpF+x8D3/gda5nUCQL2PgXy2jNG4U7/Rc9BGEv9+CAJd0YyGCROUBKs9v49Hg8huw3aih5Bf5TAVw==", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^3.5.3", + "destr": "^2.0.2", + "h3": "^1.8.2", + "ioredis": "^5.3.2", + "listhen": "^1.5.5", + "lru-cache": "^10.0.2", + "mri": "^1.2.0", + "node-fetch-native": "^1.4.1", + "ofetch": "^1.3.3", + "ufo": "^1.3.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.4.1", + "@azure/cosmos": "^4.0.0", + "@azure/data-tables": "^13.2.2", + "@azure/identity": "^3.3.2", + "@azure/keyvault-secrets": "^4.7.0", + "@azure/storage-blob": "^12.16.0", + "@capacitor/preferences": "^5.0.6", + "@netlify/blobs": "^6.2.0", + "@planetscale/database": "^1.11.0", + "@upstash/redis": "^1.23.4", + "@vercel/kv": "^0.2.3", + "idb-keyval": "^6.2.1" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "idb-keyval": { + "optional": true + } + } + }, + "node_modules/unstorage/node_modules/lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/untun": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/untun/-/untun-0.1.3.tgz", + "integrity": "sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==", + "dependencies": { + "citty": "^0.1.5", + "consola": "^3.2.3", + "pathe": "^1.1.1" + }, + "bin": { + "untun": "bin/untun.mjs" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uqr": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/uqr/-/uqr-0.1.2.tgz", + "integrity": "sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/vite": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", + "dev": true, + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/when-exit": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.2.tgz", + "integrity": "sha512-u9J+toaf3CCxCAzM/484qNAxQE75rFdVgiFEEV8Xps2gzYhf0tx73s1WXDQhkwV17E3MxRMz40m7Ekd2/121Lg==" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + } + } } diff --git a/frontend/package.json b/package.json similarity index 97% rename from frontend/package.json rename to package.json index 77ff398e..eb16d39e 100644 --- a/frontend/package.json +++ b/package.json @@ -35,7 +35,7 @@ }, "devDependencies": { "@tauri-apps/api": "^2.0.0-beta.1", - "@tauri-apps/cli": "^2.0.0-beta.0", + "@tauri-apps/cli": "^2.0.0-beta.1", "@types/conf": "^3.0.0", "@types/i18next": "^13.0.0", "@types/node": "^18.7.10", @@ -52,4 +52,4 @@ "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" } -} \ No newline at end of file +} diff --git a/frontend/public/a-icon.svg b/public/a-icon.svg similarity index 100% rename from frontend/public/a-icon.svg rename to public/a-icon.svg diff --git a/frontend/public/locales/de/translation.json b/public/locales/de/translation.json similarity index 100% rename from frontend/public/locales/de/translation.json rename to public/locales/de/translation.json diff --git a/frontend/public/locales/en/translation.json b/public/locales/en/translation.json similarity index 100% rename from frontend/public/locales/en/translation.json rename to public/locales/en/translation.json diff --git a/frontend/public/locales/es/translation.json b/public/locales/es/translation.json similarity index 100% rename from frontend/public/locales/es/translation.json rename to public/locales/es/translation.json diff --git a/frontend/public/locales/et/translation.json b/public/locales/et/translation.json similarity index 100% rename from frontend/public/locales/et/translation.json rename to public/locales/et/translation.json diff --git a/frontend/public/locales/it/translation.json b/public/locales/it/translation.json similarity index 100% rename from frontend/public/locales/it/translation.json rename to public/locales/it/translation.json diff --git a/frontend/public/locales/ja/translation.json b/public/locales/ja/translation.json similarity index 100% rename from frontend/public/locales/ja/translation.json rename to public/locales/ja/translation.json diff --git a/frontend/public/locales/lt/translation.json b/public/locales/lt/translation.json similarity index 100% rename from frontend/public/locales/lt/translation.json rename to public/locales/lt/translation.json diff --git a/frontend/public/locales/lv/translation.json b/public/locales/lv/translation.json similarity index 100% rename from frontend/public/locales/lv/translation.json rename to public/locales/lv/translation.json diff --git a/frontend/public/locales/nl/translation.json b/public/locales/nl/translation.json similarity index 100% rename from frontend/public/locales/nl/translation.json rename to public/locales/nl/translation.json diff --git a/frontend/public/locales/ru/translation.json b/public/locales/ru/translation.json similarity index 100% rename from frontend/public/locales/ru/translation.json rename to public/locales/ru/translation.json diff --git a/frontend/public/locales/tr/translation.json b/public/locales/tr/translation.json similarity index 100% rename from frontend/public/locales/tr/translation.json rename to public/locales/tr/translation.json diff --git a/frontend/public/locales/zh-CN/translation.json b/public/locales/zh-CN/translation.json similarity index 100% rename from frontend/public/locales/zh-CN/translation.json rename to public/locales/zh-CN/translation.json diff --git a/frontend/public/locales/zh-TW/translation.json b/public/locales/zh-TW/translation.json similarity index 100% rename from frontend/public/locales/zh-TW/translation.json rename to public/locales/zh-TW/translation.json diff --git a/frontend/public/tauri.svg b/public/tauri.svg similarity index 100% rename from frontend/public/tauri.svg rename to public/tauri.svg diff --git a/frontend/public/vite.svg b/public/vite.svg similarity index 100% rename from frontend/public/vite.svg rename to public/vite.svg diff --git a/frontend/public/wallet-connect-screens/wallet-connect.html b/public/wallet-connect-screens/wallet-connect.html similarity index 100% rename from frontend/public/wallet-connect-screens/wallet-connect.html rename to public/wallet-connect-screens/wallet-connect.html diff --git a/frontend/public/wallet-connect-screens/wallet-connect.js b/public/wallet-connect-screens/wallet-connect.js similarity index 100% rename from frontend/public/wallet-connect-screens/wallet-connect.js rename to public/wallet-connect-screens/wallet-connect.js diff --git a/frontend/public/wc-images/balance.svg b/public/wc-images/balance.svg similarity index 100% rename from frontend/public/wc-images/balance.svg rename to public/wc-images/balance.svg diff --git a/frontend/public/wc-images/connect.svg b/public/wc-images/connect.svg similarity index 100% rename from frontend/public/wc-images/connect.svg rename to public/wc-images/connect.svg diff --git a/frontend/public/wc-images/decrypt.svg b/public/wc-images/decrypt.svg similarity index 100% rename from frontend/public/wc-images/decrypt.svg rename to public/wc-images/decrypt.svg diff --git a/frontend/public/wc-images/deploy.svg b/public/wc-images/deploy.svg similarity index 100% rename from frontend/public/wc-images/deploy.svg rename to public/wc-images/deploy.svg diff --git a/frontend/public/wc-images/execute.svg b/public/wc-images/execute.svg similarity index 100% rename from frontend/public/wc-images/execute.svg rename to public/wc-images/execute.svg diff --git a/frontend/public/wc-images/sign.svg b/public/wc-images/sign.svg similarity index 100% rename from frontend/public/wc-images/sign.svg rename to public/wc-images/sign.svg diff --git a/frontend/public/wc-images/transactions.svg b/public/wc-images/transactions.svg similarity index 100% rename from frontend/public/wc-images/transactions.svg rename to public/wc-images/transactions.svg diff --git a/frontend/public/wc-images/tx.svg b/public/wc-images/tx.svg similarity index 100% rename from frontend/public/wc-images/tx.svg rename to public/wc-images/tx.svg diff --git a/frontend/src/App.tsx b/src/App.tsx similarity index 100% rename from frontend/src/App.tsx rename to src/App.tsx diff --git a/frontend/src/assets/dapps/ans.svg b/src/assets/dapps/ans.svg similarity index 100% rename from frontend/src/assets/dapps/ans.svg rename to src/assets/dapps/ans.svg diff --git a/frontend/src/assets/dapps/arcane.svg b/src/assets/dapps/arcane.svg similarity index 100% rename from frontend/src/assets/dapps/arcane.svg rename to src/assets/dapps/arcane.svg diff --git a/frontend/src/assets/dapps/dapps.ts b/src/assets/dapps/dapps.ts similarity index 100% rename from frontend/src/assets/dapps/dapps.ts rename to src/assets/dapps/dapps.ts diff --git a/frontend/src/assets/dapps/shadowfi.png b/src/assets/dapps/shadowfi.png similarity index 100% rename from frontend/src/assets/dapps/shadowfi.png rename to src/assets/dapps/shadowfi.png diff --git a/frontend/src/assets/dapps/staking.png b/src/assets/dapps/staking.png similarity index 100% rename from frontend/src/assets/dapps/staking.png rename to src/assets/dapps/staking.png diff --git a/frontend/src/assets/fonts/DMsans/DMSans-Bold.ttf b/src/assets/fonts/DMsans/DMSans-Bold.ttf similarity index 100% rename from frontend/src/assets/fonts/DMsans/DMSans-Bold.ttf rename to src/assets/fonts/DMsans/DMSans-Bold.ttf diff --git a/frontend/src/assets/fonts/DMsans/DMSans-ExtraBold.ttf b/src/assets/fonts/DMsans/DMSans-ExtraBold.ttf similarity index 100% rename from frontend/src/assets/fonts/DMsans/DMSans-ExtraBold.ttf rename to src/assets/fonts/DMsans/DMSans-ExtraBold.ttf diff --git a/frontend/src/assets/fonts/DMsans/DMSans-ExtraLight.ttf b/src/assets/fonts/DMsans/DMSans-ExtraLight.ttf similarity index 100% rename from frontend/src/assets/fonts/DMsans/DMSans-ExtraLight.ttf rename to src/assets/fonts/DMsans/DMSans-ExtraLight.ttf diff --git a/frontend/src/assets/fonts/DMsans/DMSans-Italic.ttf b/src/assets/fonts/DMsans/DMSans-Italic.ttf similarity index 100% rename from frontend/src/assets/fonts/DMsans/DMSans-Italic.ttf rename to src/assets/fonts/DMsans/DMSans-Italic.ttf diff --git a/frontend/src/assets/fonts/DMsans/DMSans-Light.ttf b/src/assets/fonts/DMsans/DMSans-Light.ttf similarity index 100% rename from frontend/src/assets/fonts/DMsans/DMSans-Light.ttf rename to src/assets/fonts/DMsans/DMSans-Light.ttf diff --git a/frontend/src/assets/fonts/DMsans/DMSans-Medium.ttf b/src/assets/fonts/DMsans/DMSans-Medium.ttf similarity index 100% rename from frontend/src/assets/fonts/DMsans/DMSans-Medium.ttf rename to src/assets/fonts/DMsans/DMSans-Medium.ttf diff --git a/frontend/src/assets/fonts/DMsans/DMSans-Regular.ttf b/src/assets/fonts/DMsans/DMSans-Regular.ttf similarity index 100% rename from frontend/src/assets/fonts/DMsans/DMSans-Regular.ttf rename to src/assets/fonts/DMsans/DMSans-Regular.ttf diff --git a/frontend/src/assets/fonts/DMsans/DMSans-SemiBold.ttf b/src/assets/fonts/DMsans/DMSans-SemiBold.ttf similarity index 100% rename from frontend/src/assets/fonts/DMsans/DMSans-SemiBold.ttf rename to src/assets/fonts/DMsans/DMSans-SemiBold.ttf diff --git a/frontend/src/assets/fonts/DMsans/DMSans-Thin.ttf b/src/assets/fonts/DMsans/DMSans-Thin.ttf similarity index 100% rename from frontend/src/assets/fonts/DMsans/DMSans-Thin.ttf rename to src/assets/fonts/DMsans/DMSans-Thin.ttf diff --git a/frontend/src/assets/icons/contracts/house-loan.svg b/src/assets/icons/contracts/house-loan.svg similarity index 100% rename from frontend/src/assets/icons/contracts/house-loan.svg rename to src/assets/icons/contracts/house-loan.svg diff --git a/frontend/src/assets/icons/contracts/loan-icon.svg b/src/assets/icons/contracts/loan-icon.svg similarity index 100% rename from frontend/src/assets/icons/contracts/loan-icon.svg rename to src/assets/icons/contracts/loan-icon.svg diff --git a/frontend/src/assets/icons/contracts/rent-icon.svg b/src/assets/icons/contracts/rent-icon.svg similarity index 100% rename from frontend/src/assets/icons/contracts/rent-icon.svg rename to src/assets/icons/contracts/rent-icon.svg diff --git a/frontend/src/assets/icons/contracts/sale-icon.svg b/src/assets/icons/contracts/sale-icon.svg similarity index 100% rename from frontend/src/assets/icons/contracts/sale-icon.svg rename to src/assets/icons/contracts/sale-icon.svg diff --git a/frontend/src/assets/icons/contracts/service-icon.svg b/src/assets/icons/contracts/service-icon.svg similarity index 100% rename from frontend/src/assets/icons/contracts/service-icon.svg rename to src/assets/icons/contracts/service-icon.svg diff --git a/frontend/src/assets/icons/contracts/web-dev-icon.svg b/src/assets/icons/contracts/web-dev-icon.svg similarity index 100% rename from frontend/src/assets/icons/contracts/web-dev-icon.svg rename to src/assets/icons/contracts/web-dev-icon.svg diff --git a/frontend/src/assets/icons/hub-icon-green.svg b/src/assets/icons/hub-icon-green.svg similarity index 100% rename from frontend/src/assets/icons/hub-icon-green.svg rename to src/assets/icons/hub-icon-green.svg diff --git a/frontend/src/assets/icons/hub-icon.svg b/src/assets/icons/hub-icon.svg similarity index 100% rename from frontend/src/assets/icons/hub-icon.svg rename to src/assets/icons/hub-icon.svg diff --git a/frontend/src/assets/icons/notification.svg b/src/assets/icons/notification.svg similarity index 100% rename from frontend/src/assets/icons/notification.svg rename to src/assets/icons/notification.svg diff --git a/frontend/src/assets/icons/qr-code.svg b/src/assets/icons/qr-code.svg similarity index 100% rename from frontend/src/assets/icons/qr-code.svg rename to src/assets/icons/qr-code.svg diff --git a/frontend/src/assets/icons/tokens/aleo.svg b/src/assets/icons/tokens/aleo.svg similarity index 100% rename from frontend/src/assets/icons/tokens/aleo.svg rename to src/assets/icons/tokens/aleo.svg diff --git a/frontend/src/assets/icons/tokens/usdt.svg b/src/assets/icons/tokens/usdt.svg similarity index 100% rename from frontend/src/assets/icons/tokens/usdt.svg rename to src/assets/icons/tokens/usdt.svg diff --git a/frontend/src/assets/images/backgrounds/sign-up-bg.jpeg b/src/assets/images/backgrounds/sign-up-bg.jpeg similarity index 100% rename from frontend/src/assets/images/backgrounds/sign-up-bg.jpeg rename to src/assets/images/backgrounds/sign-up-bg.jpeg diff --git a/frontend/src/assets/images/backgrounds/sign-up-bg.svg b/src/assets/images/backgrounds/sign-up-bg.svg similarity index 100% rename from frontend/src/assets/images/backgrounds/sign-up-bg.svg rename to src/assets/images/backgrounds/sign-up-bg.svg diff --git a/frontend/src/assets/images/backup.svg b/src/assets/images/backup.svg similarity index 100% rename from frontend/src/assets/images/backup.svg rename to src/assets/images/backup.svg diff --git a/frontend/src/assets/images/login-dalle.svg b/src/assets/images/login-dalle.svg similarity index 100% rename from frontend/src/assets/images/login-dalle.svg rename to src/assets/images/login-dalle.svg diff --git a/frontend/src/assets/images/tokens/ALEO.svg b/src/assets/images/tokens/ALEO.svg similarity index 100% rename from frontend/src/assets/images/tokens/ALEO.svg rename to src/assets/images/tokens/ALEO.svg diff --git a/frontend/src/assets/images/tokens/USDC.svg b/src/assets/images/tokens/USDC.svg similarity index 100% rename from frontend/src/assets/images/tokens/USDC.svg rename to src/assets/images/tokens/USDC.svg diff --git a/frontend/src/assets/logo/a-icon.svg b/src/assets/logo/a-icon.svg similarity index 100% rename from frontend/src/assets/logo/a-icon.svg rename to src/assets/logo/a-icon.svg diff --git a/frontend/src/assets/logo/desktop-full-logo.svg b/src/assets/logo/desktop-full-logo.svg similarity index 100% rename from frontend/src/assets/logo/desktop-full-logo.svg rename to src/assets/logo/desktop-full-logo.svg diff --git a/frontend/src/assets/logo/full-logo.svg b/src/assets/logo/full-logo.svg similarity index 100% rename from frontend/src/assets/logo/full-logo.svg rename to src/assets/logo/full-logo.svg diff --git a/frontend/src/assets/notification-icons/nannouncement.svg b/src/assets/notification-icons/nannouncement.svg similarity index 100% rename from frontend/src/assets/notification-icons/nannouncement.svg rename to src/assets/notification-icons/nannouncement.svg diff --git a/frontend/src/assets/notification-icons/ncontract.svg b/src/assets/notification-icons/ncontract.svg similarity index 100% rename from frontend/src/assets/notification-icons/ncontract.svg rename to src/assets/notification-icons/ncontract.svg diff --git a/frontend/src/assets/notification-icons/nheart.svg b/src/assets/notification-icons/nheart.svg similarity index 100% rename from frontend/src/assets/notification-icons/nheart.svg rename to src/assets/notification-icons/nheart.svg diff --git a/frontend/src/assets/notification-icons/nloan_accepted.svg b/src/assets/notification-icons/nloan_accepted.svg similarity index 100% rename from frontend/src/assets/notification-icons/nloan_accepted.svg rename to src/assets/notification-icons/nloan_accepted.svg diff --git a/frontend/src/assets/notification-icons/nloan_request.svg b/src/assets/notification-icons/nloan_request.svg similarity index 100% rename from frontend/src/assets/notification-icons/nloan_request.svg rename to src/assets/notification-icons/nloan_request.svg diff --git a/frontend/src/assets/notification-icons/npayment.svg b/src/assets/notification-icons/npayment.svg similarity index 100% rename from frontend/src/assets/notification-icons/npayment.svg rename to src/assets/notification-icons/npayment.svg diff --git a/frontend/src/assets/react.svg b/src/assets/react.svg similarity index 100% rename from frontend/src/assets/react.svg rename to src/assets/react.svg diff --git a/frontend/src/browser/nova_browser.tsx b/src/browser/nova_browser.tsx similarity index 100% rename from frontend/src/browser/nova_browser.tsx rename to src/browser/nova_browser.tsx diff --git a/frontend/src/components/account/details.tsx b/src/components/account/details.tsx similarity index 100% rename from frontend/src/components/account/details.tsx rename to src/components/account/details.tsx diff --git a/frontend/src/components/account/profile-header.tsx b/src/components/account/profile-header.tsx similarity index 100% rename from frontend/src/components/account/profile-header.tsx rename to src/components/account/profile-header.tsx diff --git a/frontend/src/components/assets/asset.tsx b/src/components/assets/asset.tsx similarity index 100% rename from frontend/src/components/assets/asset.tsx rename to src/components/assets/asset.tsx diff --git a/frontend/src/components/assets/asset_drawer.tsx b/src/components/assets/asset_drawer.tsx similarity index 100% rename from frontend/src/components/assets/asset_drawer.tsx rename to src/components/assets/asset_drawer.tsx diff --git a/frontend/src/components/assets/balances.tsx b/src/components/assets/balances.tsx similarity index 100% rename from frontend/src/components/assets/balances.tsx rename to src/components/assets/balances.tsx diff --git a/frontend/src/components/backup/backup_dialog.tsx b/src/components/backup/backup_dialog.tsx similarity index 100% rename from frontend/src/components/backup/backup_dialog.tsx rename to src/components/backup/backup_dialog.tsx diff --git a/frontend/src/components/balance.tsx b/src/components/balance.tsx similarity index 100% rename from frontend/src/components/balance.tsx rename to src/components/balance.tsx diff --git a/frontend/src/components/buttons/back.tsx b/src/components/buttons/back.tsx similarity index 100% rename from frontend/src/components/buttons/back.tsx rename to src/components/buttons/back.tsx diff --git a/frontend/src/components/buttons/cta.tsx b/src/components/buttons/cta.tsx similarity index 100% rename from frontend/src/components/buttons/cta.tsx rename to src/components/buttons/cta.tsx diff --git a/frontend/src/components/buttons/home_options.tsx b/src/components/buttons/home_options.tsx similarity index 100% rename from frontend/src/components/buttons/home_options.tsx rename to src/components/buttons/home_options.tsx diff --git a/frontend/src/components/buttons/login-button.tsx b/src/components/buttons/login-button.tsx similarity index 100% rename from frontend/src/components/buttons/login-button.tsx rename to src/components/buttons/login-button.tsx diff --git a/frontend/src/components/buttons/secure-button.tsx b/src/components/buttons/secure-button.tsx similarity index 100% rename from frontend/src/components/buttons/secure-button.tsx rename to src/components/buttons/secure-button.tsx diff --git a/frontend/src/components/buttons/settings-button.tsx b/src/components/buttons/settings-button.tsx similarity index 100% rename from frontend/src/components/buttons/settings-button.tsx rename to src/components/buttons/settings-button.tsx diff --git a/frontend/src/components/buttons/sign-up-button.tsx b/src/components/buttons/sign-up-button.tsx similarity index 100% rename from frontend/src/components/buttons/sign-up-button.tsx rename to src/components/buttons/sign-up-button.tsx diff --git a/frontend/src/components/buttons/transfer_cta.tsx b/src/components/buttons/transfer_cta.tsx similarity index 100% rename from frontend/src/components/buttons/transfer_cta.tsx rename to src/components/buttons/transfer_cta.tsx diff --git a/frontend/src/components/chat/add_contact.tsx b/src/components/chat/add_contact.tsx similarity index 100% rename from frontend/src/components/chat/add_contact.tsx rename to src/components/chat/add_contact.tsx diff --git a/frontend/src/components/chat/friend.tsx b/src/components/chat/friend.tsx similarity index 100% rename from frontend/src/components/chat/friend.tsx rename to src/components/chat/friend.tsx diff --git a/frontend/src/components/chat/message.tsx b/src/components/chat/message.tsx similarity index 100% rename from frontend/src/components/chat/message.tsx rename to src/components/chat/message.tsx diff --git a/frontend/src/components/chat/message_bar.tsx b/src/components/chat/message_bar.tsx similarity index 100% rename from frontend/src/components/chat/message_bar.tsx rename to src/components/chat/message_bar.tsx diff --git a/frontend/src/components/chat/new_transfer.tsx b/src/components/chat/new_transfer.tsx similarity index 100% rename from frontend/src/components/chat/new_transfer.tsx rename to src/components/chat/new_transfer.tsx diff --git a/frontend/src/components/chat/room.tsx b/src/components/chat/room.tsx similarity index 100% rename from frontend/src/components/chat/room.tsx rename to src/components/chat/room.tsx diff --git a/frontend/src/components/contracts/contractItem.tsx b/src/components/contracts/contractItem.tsx similarity index 100% rename from frontend/src/components/contracts/contractItem.tsx rename to src/components/contracts/contractItem.tsx diff --git a/frontend/src/components/contracts/contract_bottom_bar.tsx b/src/components/contracts/contract_bottom_bar.tsx similarity index 100% rename from frontend/src/components/contracts/contract_bottom_bar.tsx rename to src/components/contracts/contract_bottom_bar.tsx diff --git a/frontend/src/components/dApps/dapp.tsx b/src/components/dApps/dapp.tsx similarity index 100% rename from frontend/src/components/dApps/dapp.tsx rename to src/components/dApps/dapp.tsx diff --git a/frontend/src/components/dialogs/delete.tsx b/src/components/dialogs/delete.tsx similarity index 100% rename from frontend/src/components/dialogs/delete.tsx rename to src/components/dialogs/delete.tsx diff --git a/frontend/src/components/dialogs/disable_backup.tsx b/src/components/dialogs/disable_backup.tsx similarity index 100% rename from frontend/src/components/dialogs/disable_backup.tsx rename to src/components/dialogs/disable_backup.tsx diff --git a/frontend/src/components/dialogs/keys/get_private_key.tsx b/src/components/dialogs/keys/get_private_key.tsx similarity index 100% rename from frontend/src/components/dialogs/keys/get_private_key.tsx rename to src/components/dialogs/keys/get_private_key.tsx diff --git a/frontend/src/components/dialogs/keys/get_seed_phrase.tsx b/src/components/dialogs/keys/get_seed_phrase.tsx similarity index 100% rename from frontend/src/components/dialogs/keys/get_seed_phrase.tsx rename to src/components/dialogs/keys/get_seed_phrase.tsx diff --git a/frontend/src/components/dialogs/keys/get_viewing_key.tsx b/src/components/dialogs/keys/get_viewing_key.tsx similarity index 100% rename from frontend/src/components/dialogs/keys/get_viewing_key.tsx rename to src/components/dialogs/keys/get_viewing_key.tsx diff --git a/frontend/src/components/dialogs/logout.tsx b/src/components/dialogs/logout.tsx similarity index 100% rename from frontend/src/components/dialogs/logout.tsx rename to src/components/dialogs/logout.tsx diff --git a/frontend/src/components/dialogs/reauth.tsx b/src/components/dialogs/reauth.tsx similarity index 100% rename from frontend/src/components/dialogs/reauth.tsx rename to src/components/dialogs/reauth.tsx diff --git a/frontend/src/components/dialogs/receive.tsx b/src/components/dialogs/receive.tsx similarity index 100% rename from frontend/src/components/dialogs/receive.tsx rename to src/components/dialogs/receive.tsx diff --git a/frontend/src/components/dialogs/scan_reauth.tsx b/src/components/dialogs/scan_reauth.tsx similarity index 100% rename from frontend/src/components/dialogs/scan_reauth.tsx rename to src/components/dialogs/scan_reauth.tsx diff --git a/frontend/src/components/dialogs/transfer.tsx b/src/components/dialogs/transfer.tsx similarity index 100% rename from frontend/src/components/dialogs/transfer.tsx rename to src/components/dialogs/transfer.tsx diff --git a/frontend/src/components/dialogs/username.tsx b/src/components/dialogs/username.tsx similarity index 100% rename from frontend/src/components/dialogs/username.tsx rename to src/components/dialogs/username.tsx diff --git a/frontend/src/components/events/event.tsx b/src/components/events/event.tsx similarity index 100% rename from frontend/src/components/events/event.tsx rename to src/components/events/event.tsx diff --git a/frontend/src/components/events/event_drawer.tsx b/src/components/events/event_drawer.tsx similarity index 100% rename from frontend/src/components/events/event_drawer.tsx rename to src/components/events/event_drawer.tsx diff --git a/frontend/src/components/events/explorer.tsx b/src/components/events/explorer.tsx similarity index 100% rename from frontend/src/components/events/explorer.tsx rename to src/components/events/explorer.tsx diff --git a/frontend/src/components/events/transition.tsx b/src/components/events/transition.tsx similarity index 100% rename from frontend/src/components/events/transition.tsx rename to src/components/events/transition.tsx diff --git a/frontend/src/components/header/appbar.tsx b/src/components/header/appbar.tsx similarity index 100% rename from frontend/src/components/header/appbar.tsx rename to src/components/header/appbar.tsx diff --git a/frontend/src/components/header/chat_header.tsx b/src/components/header/chat_header.tsx similarity index 100% rename from frontend/src/components/header/chat_header.tsx rename to src/components/header/chat_header.tsx diff --git a/frontend/src/components/header/contract_header.tsx b/src/components/header/contract_header.tsx similarity index 100% rename from frontend/src/components/header/contract_header.tsx rename to src/components/header/contract_header.tsx diff --git a/frontend/src/components/header/header.tsx b/src/components/header/header.tsx similarity index 100% rename from frontend/src/components/header/header.tsx rename to src/components/header/header.tsx diff --git a/frontend/src/components/header/simple_appbar.tsx b/src/components/header/simple_appbar.tsx similarity index 100% rename from frontend/src/components/header/simple_appbar.tsx rename to src/components/header/simple_appbar.tsx diff --git a/frontend/src/components/header/transfer_header.tsx b/src/components/header/transfer_header.tsx similarity index 100% rename from frontend/src/components/header/transfer_header.tsx rename to src/components/header/transfer_header.tsx diff --git a/frontend/src/components/icons/received.tsx b/src/components/icons/received.tsx similarity index 100% rename from frontend/src/components/icons/received.tsx rename to src/components/icons/received.tsx diff --git a/frontend/src/components/icons/sent.tsx b/src/components/icons/sent.tsx similarity index 100% rename from frontend/src/components/icons/sent.tsx rename to src/components/icons/sent.tsx diff --git a/frontend/src/components/loadingScreen.tsx b/src/components/loadingScreen.tsx similarity index 100% rename from frontend/src/components/loadingScreen.tsx rename to src/components/loadingScreen.tsx diff --git a/frontend/src/components/menu/options.tsx b/src/components/menu/options.tsx similarity index 100% rename from frontend/src/components/menu/options.tsx rename to src/components/menu/options.tsx diff --git a/frontend/src/components/nft.tsx b/src/components/nft.tsx similarity index 100% rename from frontend/src/components/nft.tsx rename to src/components/nft.tsx diff --git a/frontend/src/components/notifications/notification.tsx b/src/components/notifications/notification.tsx similarity index 100% rename from frontend/src/components/notifications/notification.tsx rename to src/components/notifications/notification.tsx diff --git a/frontend/src/components/notifications/slider.tsx b/src/components/notifications/slider.tsx similarity index 100% rename from frontend/src/components/notifications/slider.tsx rename to src/components/notifications/slider.tsx diff --git a/frontend/src/components/searchabar.tsx b/src/components/searchabar.tsx similarity index 100% rename from frontend/src/components/searchabar.tsx rename to src/components/searchabar.tsx diff --git a/frontend/src/components/select/language.tsx b/src/components/select/language.tsx similarity index 100% rename from frontend/src/components/select/language.tsx rename to src/components/select/language.tsx diff --git a/frontend/src/components/select/seed_length.tsx b/src/components/select/seed_length.tsx similarity index 100% rename from frontend/src/components/select/seed_length.tsx rename to src/components/select/seed_length.tsx diff --git a/frontend/src/components/settings/general.tsx b/src/components/settings/general.tsx similarity index 100% rename from frontend/src/components/settings/general.tsx rename to src/components/settings/general.tsx diff --git a/frontend/src/components/sidebar.tsx b/src/components/sidebar.tsx similarity index 100% rename from frontend/src/components/sidebar.tsx rename to src/components/sidebar.tsx diff --git a/frontend/src/components/snackbars/alerts.tsx b/src/components/snackbars/alerts.tsx similarity index 100% rename from frontend/src/components/snackbars/alerts.tsx rename to src/components/snackbars/alerts.tsx diff --git a/frontend/src/components/switch/privacy_toggle.tsx b/src/components/switch/privacy_toggle.tsx similarity index 100% rename from frontend/src/components/switch/privacy_toggle.tsx rename to src/components/switch/privacy_toggle.tsx diff --git a/frontend/src/components/textfields/white-hue.tsx b/src/components/textfields/white-hue.tsx similarity index 100% rename from frontend/src/components/textfields/white-hue.tsx rename to src/components/textfields/white-hue.tsx diff --git a/frontend/src/components/transfer/token_dropdown.tsx b/src/components/transfer/token_dropdown.tsx similarity index 100% rename from frontend/src/components/transfer/token_dropdown.tsx rename to src/components/transfer/token_dropdown.tsx diff --git a/frontend/src/components/transfer/transfer_box.tsx b/src/components/transfer/transfer_box.tsx similarity index 100% rename from frontend/src/components/transfer/transfer_box.tsx rename to src/components/transfer/transfer_box.tsx diff --git a/frontend/src/components/typography/typography.tsx b/src/components/typography/typography.tsx similarity index 100% rename from frontend/src/components/typography/typography.tsx rename to src/components/typography/typography.tsx diff --git a/frontend/src/context/EventsContext.tsx b/src/context/EventsContext.tsx similarity index 100% rename from frontend/src/context/EventsContext.tsx rename to src/context/EventsContext.tsx diff --git a/frontend/src/context/ScanContext.tsx b/src/context/ScanContext.tsx similarity index 100% rename from frontend/src/context/ScanContext.tsx rename to src/context/ScanContext.tsx diff --git a/frontend/src/context/WalletConnect.tsx b/src/context/WalletConnect.tsx similarity index 100% rename from frontend/src/context/WalletConnect.tsx rename to src/context/WalletConnect.tsx diff --git a/frontend/src/i18next-config.ts b/src/i18next-config.ts similarity index 100% rename from frontend/src/i18next-config.ts rename to src/i18next-config.ts diff --git a/frontend/src/index.css b/src/index.css similarity index 100% rename from frontend/src/index.css rename to src/index.css diff --git a/frontend/src/main.tsx b/src/main.tsx similarity index 100% rename from frontend/src/main.tsx rename to src/main.tsx diff --git a/frontend/src/services/authentication/auth.ts b/src/services/authentication/auth.ts similarity index 100% rename from frontend/src/services/authentication/auth.ts rename to src/services/authentication/auth.ts diff --git a/frontend/src/services/authentication/register.ts b/src/services/authentication/register.ts similarity index 100% rename from frontend/src/services/authentication/register.ts rename to src/services/authentication/register.ts diff --git a/frontend/src/services/events/get_events.ts b/src/services/events/get_events.ts similarity index 100% rename from frontend/src/services/events/get_events.ts rename to src/services/events/get_events.ts diff --git a/frontend/src/services/keychain/keychain.ts b/src/services/keychain/keychain.ts similarity index 100% rename from frontend/src/services/keychain/keychain.ts rename to src/services/keychain/keychain.ts diff --git a/frontend/src/services/nfts/fetch.ts b/src/services/nfts/fetch.ts similarity index 100% rename from frontend/src/services/nfts/fetch.ts rename to src/services/nfts/fetch.ts diff --git a/frontend/src/services/recovery/phrase.ts b/src/services/recovery/phrase.ts similarity index 100% rename from frontend/src/services/recovery/phrase.ts rename to src/services/recovery/phrase.ts diff --git a/frontend/src/services/scans/backup.ts b/src/services/scans/backup.ts similarity index 100% rename from frontend/src/services/scans/backup.ts rename to src/services/scans/backup.ts diff --git a/frontend/src/services/scans/blocks.ts b/src/services/scans/blocks.ts similarity index 100% rename from frontend/src/services/scans/blocks.ts rename to src/services/scans/blocks.ts diff --git a/frontend/src/services/scans/encrypted_messages.ts b/src/services/scans/encrypted_messages.ts similarity index 100% rename from frontend/src/services/scans/encrypted_messages.ts rename to src/services/scans/encrypted_messages.ts diff --git a/frontend/src/services/states/utils.ts b/src/services/states/utils.ts similarity index 100% rename from frontend/src/services/states/utils.ts rename to src/services/states/utils.ts diff --git a/frontend/src/services/storage/keys.ts b/src/services/storage/keys.ts similarity index 100% rename from frontend/src/services/storage/keys.ts rename to src/services/storage/keys.ts diff --git a/frontend/src/services/storage/localStorage.ts b/src/services/storage/localStorage.ts similarity index 100% rename from frontend/src/services/storage/localStorage.ts rename to src/services/storage/localStorage.ts diff --git a/frontend/src/services/storage/persistent.ts b/src/services/storage/persistent.ts similarity index 100% rename from frontend/src/services/storage/persistent.ts rename to src/services/storage/persistent.ts diff --git a/frontend/src/services/tokens/get_balance.ts b/src/services/tokens/get_balance.ts similarity index 100% rename from frontend/src/services/tokens/get_balance.ts rename to src/services/tokens/get_balance.ts diff --git a/frontend/src/services/tokens/get_tokens.ts b/src/services/tokens/get_tokens.ts similarity index 100% rename from frontend/src/services/tokens/get_tokens.ts rename to src/services/tokens/get_tokens.ts diff --git a/frontend/src/services/transfer/inclusion.ts b/src/services/transfer/inclusion.ts similarity index 100% rename from frontend/src/services/transfer/inclusion.ts rename to src/services/transfer/inclusion.ts diff --git a/frontend/src/services/transfer/transfers.ts b/src/services/transfer/transfers.ts similarity index 100% rename from frontend/src/services/transfer/transfers.ts rename to src/services/transfer/transfers.ts diff --git a/frontend/src/services/util/functions.ts b/src/services/util/functions.ts similarity index 100% rename from frontend/src/services/util/functions.ts rename to src/services/util/functions.ts diff --git a/frontend/src/services/util/open.ts b/src/services/util/open.ts similarity index 100% rename from frontend/src/services/util/open.ts rename to src/services/util/open.ts diff --git a/frontend/src/services/util/sign.ts b/src/services/util/sign.ts similarity index 100% rename from frontend/src/services/util/sign.ts rename to src/services/util/sign.ts diff --git a/frontend/src/services/wallet-connect/AleoWallet.ts b/src/services/wallet-connect/AleoWallet.ts similarity index 100% rename from frontend/src/services/wallet-connect/AleoWallet.ts rename to src/services/wallet-connect/AleoWallet.ts diff --git a/frontend/src/services/wallet-connect/SessionInfo.ts b/src/services/wallet-connect/SessionInfo.ts similarity index 100% rename from frontend/src/services/wallet-connect/SessionInfo.ts rename to src/services/wallet-connect/SessionInfo.ts diff --git a/frontend/src/services/wallet-connect/WCTypes.ts b/src/services/wallet-connect/WCTypes.ts similarity index 100% rename from frontend/src/services/wallet-connect/WCTypes.ts rename to src/services/wallet-connect/WCTypes.ts diff --git a/frontend/src/services/wallet-connect/WalletConnectManager.ts b/src/services/wallet-connect/WalletConnectManager.ts similarity index 100% rename from frontend/src/services/wallet-connect/WalletConnectManager.ts rename to src/services/wallet-connect/WalletConnectManager.ts diff --git a/frontend/src/styles/animations.css b/src/styles/animations.css similarity index 100% rename from frontend/src/styles/animations.css rename to src/styles/animations.css diff --git a/frontend/src/styles/shapes.css b/src/styles/shapes.css similarity index 100% rename from frontend/src/styles/shapes.css rename to src/styles/shapes.css diff --git a/frontend/src/styles/theme.ts b/src/styles/theme.ts similarity index 100% rename from frontend/src/styles/theme.ts rename to src/styles/theme.ts diff --git a/frontend/src/types/assets/asset.ts b/src/types/assets/asset.ts similarity index 100% rename from frontend/src/types/assets/asset.ts rename to src/types/assets/asset.ts diff --git a/frontend/src/types/auth.ts b/src/types/auth.ts similarity index 100% rename from frontend/src/types/auth.ts rename to src/types/auth.ts diff --git a/frontend/src/types/avail-events/event.ts b/src/types/avail-events/event.ts similarity index 100% rename from frontend/src/types/avail-events/event.ts rename to src/types/avail-events/event.ts diff --git a/frontend/src/types/chat/messages.ts b/src/types/chat/messages.ts similarity index 100% rename from frontend/src/types/chat/messages.ts rename to src/types/chat/messages.ts diff --git a/frontend/src/types/chat/room.ts b/src/types/chat/room.ts similarity index 100% rename from frontend/src/types/chat/room.ts rename to src/types/chat/room.ts diff --git a/frontend/src/types/contracts/service.ts b/src/types/contracts/service.ts similarity index 100% rename from frontend/src/types/contracts/service.ts rename to src/types/contracts/service.ts diff --git a/frontend/src/types/errors.ts b/src/types/errors.ts similarity index 100% rename from frontend/src/types/errors.ts rename to src/types/errors.ts diff --git a/frontend/src/types/events.ts b/src/types/events.ts similarity index 100% rename from frontend/src/types/events.ts rename to src/types/events.ts diff --git a/frontend/src/types/languages.ts b/src/types/languages.ts similarity index 100% rename from frontend/src/types/languages.ts rename to src/types/languages.ts diff --git a/frontend/src/types/nfts/nft.ts b/src/types/nfts/nft.ts similarity index 100% rename from frontend/src/types/nfts/nft.ts rename to src/types/nfts/nft.ts diff --git a/frontend/src/types/notification.tsx b/src/types/notification.tsx similarity index 100% rename from frontend/src/types/notification.tsx rename to src/types/notification.tsx diff --git a/frontend/src/types/transfer_props/tokens.ts b/src/types/transfer_props/tokens.ts similarity index 100% rename from frontend/src/types/transfer_props/tokens.ts rename to src/types/transfer_props/tokens.ts diff --git a/frontend/src/types/user_preferences.ts b/src/types/user_preferences.ts similarity index 100% rename from frontend/src/types/user_preferences.ts rename to src/types/user_preferences.ts diff --git a/frontend/src/views-desktop/activity.tsx b/src/views-desktop/activity.tsx similarity index 100% rename from frontend/src/views-desktop/activity.tsx rename to src/views-desktop/activity.tsx diff --git a/frontend/src/views-desktop/browser.tsx b/src/views-desktop/browser.tsx similarity index 100% rename from frontend/src/views-desktop/browser.tsx rename to src/views-desktop/browser.tsx diff --git a/frontend/src/views-desktop/entrypoint.tsx b/src/views-desktop/entrypoint.tsx similarity index 100% rename from frontend/src/views-desktop/entrypoint.tsx rename to src/views-desktop/entrypoint.tsx diff --git a/frontend/src/views-desktop/home-desktop.tsx b/src/views-desktop/home-desktop.tsx similarity index 100% rename from frontend/src/views-desktop/home-desktop.tsx rename to src/views-desktop/home-desktop.tsx diff --git a/frontend/src/views-desktop/login.tsx b/src/views-desktop/login.tsx similarity index 100% rename from frontend/src/views-desktop/login.tsx rename to src/views-desktop/login.tsx diff --git a/frontend/src/views-desktop/nft.tsx b/src/views-desktop/nft.tsx similarity index 100% rename from frontend/src/views-desktop/nft.tsx rename to src/views-desktop/nft.tsx diff --git a/frontend/src/views-desktop/oops.tsx b/src/views-desktop/oops.tsx similarity index 100% rename from frontend/src/views-desktop/oops.tsx rename to src/views-desktop/oops.tsx diff --git a/frontend/src/views-desktop/privacy-policy.tsx b/src/views-desktop/privacy-policy.tsx similarity index 100% rename from frontend/src/views-desktop/privacy-policy.tsx rename to src/views-desktop/privacy-policy.tsx diff --git a/frontend/src/views-desktop/recovery.tsx b/src/views-desktop/recovery.tsx similarity index 100% rename from frontend/src/views-desktop/recovery.tsx rename to src/views-desktop/recovery.tsx diff --git a/frontend/src/views-desktop/register.tsx b/src/views-desktop/register.tsx similarity index 100% rename from frontend/src/views-desktop/register.tsx rename to src/views-desktop/register.tsx diff --git a/frontend/src/views-desktop/reusable/bottom-nav.tsx b/src/views-desktop/reusable/bottom-nav.tsx similarity index 100% rename from frontend/src/views-desktop/reusable/bottom-nav.tsx rename to src/views-desktop/reusable/bottom-nav.tsx diff --git a/frontend/src/views-desktop/reusable/layout.tsx b/src/views-desktop/reusable/layout.tsx similarity index 100% rename from frontend/src/views-desktop/reusable/layout.tsx rename to src/views-desktop/reusable/layout.tsx diff --git a/frontend/src/views-desktop/seedphrase.tsx b/src/views-desktop/seedphrase.tsx similarity index 100% rename from frontend/src/views-desktop/seedphrase.tsx rename to src/views-desktop/seedphrase.tsx diff --git a/frontend/src/views-desktop/send.tsx b/src/views-desktop/send.tsx similarity index 100% rename from frontend/src/views-desktop/send.tsx rename to src/views-desktop/send.tsx diff --git a/frontend/src/views-desktop/settings.tsx b/src/views-desktop/settings.tsx similarity index 100% rename from frontend/src/views-desktop/settings.tsx rename to src/views-desktop/settings.tsx diff --git a/frontend/src/views-desktop/terms-and-conditions.tsx b/src/views-desktop/terms-and-conditions.tsx similarity index 100% rename from frontend/src/views-desktop/terms-and-conditions.tsx rename to src/views-desktop/terms-and-conditions.tsx diff --git a/frontend/src/views-desktop/verify.tsx b/src/views-desktop/verify.tsx similarity index 100% rename from frontend/src/views-desktop/verify.tsx rename to src/views-desktop/verify.tsx diff --git a/frontend/src/vite-env.d.ts b/src/vite-env.d.ts similarity index 100% rename from frontend/src/vite-env.d.ts rename to src/vite-env.d.ts diff --git a/frontend/tsconfig.json b/tsconfig.json similarity index 100% rename from frontend/tsconfig.json rename to tsconfig.json diff --git a/frontend/tsconfig.node.json b/tsconfig.node.json similarity index 100% rename from frontend/tsconfig.node.json rename to tsconfig.node.json diff --git a/frontend/vite.config.ts b/vite.config.ts similarity index 100% rename from frontend/vite.config.ts rename to vite.config.ts From a966c870bab645cb515c5132c6b50174cbf2e78a Mon Sep 17 00:00:00 2001 From: girogio Date: Tue, 20 Feb 2024 09:52:53 +0100 Subject: [PATCH 3/3] Fixed dist path resolution --- src-tauri/tauri.conf.json | 2 +- src-tauri/tauri.windows.conf.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index cd0634cc..dc6d8a57 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -5,7 +5,7 @@ "beforeDevCommand": "npm i && npm run dev", "beforeBuildCommand": "npm i && npm run build", "devUrl": "http://localhost:1420", - "frontendDist": "dist" + "frontendDist": "../dist" }, "bundle": { "active": true, diff --git a/src-tauri/tauri.windows.conf.json b/src-tauri/tauri.windows.conf.json index e18a62d7..627fccdf 100644 --- a/src-tauri/tauri.windows.conf.json +++ b/src-tauri/tauri.windows.conf.json @@ -1,7 +1,7 @@ { "build": { - "beforeDevCommand": "cd .\\frontend\\ & npm i & npm run dev", - "beforeBuildCommand": "cd .\\frontend\\ & npm i & npm run build", - "frontendDist": "..\\frontend\\dist" + "beforeDevCommand": "npm i & npm run dev", + "beforeBuildCommand": "npm i & npm run build", + "frontendDist": "..\\dist\\" } -} \ No newline at end of file +}