From 1079258ae94687ff6073790d86b2be7cbbb85042 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Tue, 19 Mar 2024 20:38:24 +0100 Subject: [PATCH 01/10] feat: eth wallet contract implementation --- .../implementation/Cargo.lock | 5173 +++++++++++++++++ .../implementation/Cargo.toml | 37 + .../address-registrar/Cargo.toml | 15 + .../address-registrar/src/lib.rs | 76 + .../implementation/wallet-contract/Cargo.toml | 29 + .../src/ADDRESS_REGISTRAR_ACCOUNT_ID | 1 + .../wallet-contract/src/error.rs | 167 + .../wallet-contract/src/eth_emulation.rs | 87 + .../wallet-contract/src/ethabi_utils.rs | 254 + .../wallet-contract/src/internal.rs | 286 + .../implementation/wallet-contract/src/lib.rs | 245 + .../wallet-contract/src/near_action.rs | 87 + .../wallet-contract/src/tests/caller_error.rs | 126 + .../wallet-contract/src/tests/emulation.rs | 184 + .../wallet-contract/src/tests/mod.rs | 9 + .../wallet-contract/src/tests/relayer.rs | 337 ++ .../wallet-contract/src/tests/res/hello.wasm | Bin 0 -> 215153 bytes .../wallet-contract/src/tests/res/nep141.wasm | Bin 0 -> 180658 bytes .../wallet-contract/src/tests/sanity.rs | 100 + .../wallet-contract/src/tests/user_error.rs | 446 ++ .../wallet-contract/src/tests/utils/codec.rs | 86 + .../wallet-contract/src/tests/utils/crypto.rs | 25 + .../wallet-contract/src/tests/utils/mod.rs | 66 + .../wallet-contract/src/tests/utils/nep141.rs | 67 + .../src/tests/utils/test_context.rs | 267 + .../wallet-contract/src/types.rs | 264 + .../res/wallet_contract.wasm | Bin 94343 -> 310376 bytes .../wallet-contract/Cargo.lock | 1529 ----- .../wallet-contract/Cargo.toml | 30 - .../wallet-contract/src/lib.rs | 53 - 30 files changed, 8434 insertions(+), 1612 deletions(-) create mode 100644 runtime/near-wallet-contract/implementation/Cargo.lock create mode 100644 runtime/near-wallet-contract/implementation/Cargo.toml create mode 100644 runtime/near-wallet-contract/implementation/address-registrar/Cargo.toml create mode 100644 runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/Cargo.toml create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/ADDRESS_REGISTRAR_ACCOUNT_ID create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/error.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/ethabi_utils.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/near_action.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/caller_error.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/mod.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs create mode 100755 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/res/hello.wasm create mode 100755 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/res/nep141.wasm create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/sanity.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/codec.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/crypto.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/nep141.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs create mode 100644 runtime/near-wallet-contract/implementation/wallet-contract/src/types.rs delete mode 100644 runtime/near-wallet-contract/wallet-contract/Cargo.lock delete mode 100644 runtime/near-wallet-contract/wallet-contract/Cargo.toml delete mode 100644 runtime/near-wallet-contract/wallet-contract/src/lib.rs diff --git a/runtime/near-wallet-contract/implementation/Cargo.lock b/runtime/near-wallet-contract/implementation/Cargo.lock new file mode 100644 index 00000000000..b8eeb1294df --- /dev/null +++ b/runtime/near-wallet-contract/implementation/Cargo.lock @@ -0,0 +1,5173 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + +[[package]] +name = "actix" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb72882332b6d6282f428b77ba0358cb2687e61a6f6df6a6d3871e8a177c2d4f" +dependencies = [ + "actix-macros", + "actix-rt", + "actix_derive", + "bitflags 2.5.0", + "bytes", + "crossbeam-channel", + "futures-core", + "futures-sink", + "futures-task", + "futures-util", + "log", + "once_cell", + "parking_lot", + "pin-project-lite", + "smallvec", + "tokio", + "tokio-util 0.7.10", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn 2.0.53", +] + +[[package]] +name = "actix-rt" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli 0.28.1", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if 1.0.0", + "cipher 0.4.4", + "cpufeatures", +] + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.12", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[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.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + +[[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 = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "async-trait" +version = "0.1.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "aurora-engine-modexp" +version = "1.0.0" +source = "git+https://github.com/aurora-is-near/aurora-engine.git?rev=c03a2d8610cd27a9decb91b3bddb107db2177b29#c03a2d8610cd27a9decb91b3bddb107db2177b29" +dependencies = [ + "hex", + "num", +] + +[[package]] +name = "aurora-engine-precompiles" +version = "1.0.0" +source = "git+https://github.com/aurora-is-near/aurora-engine.git?rev=c03a2d8610cd27a9decb91b3bddb107db2177b29#c03a2d8610cd27a9decb91b3bddb107db2177b29" +dependencies = [ + "aurora-engine-modexp", + "aurora-engine-sdk", + "aurora-engine-types", + "ethabi", + "evm", + "hex", + "libsecp256k1", + "num", + "ripemd", + "sha2 0.10.8", + "sha3", + "zeropool-bn", +] + +[[package]] +name = "aurora-engine-sdk" +version = "1.0.0" +source = "git+https://github.com/aurora-is-near/aurora-engine.git?rev=c03a2d8610cd27a9decb91b3bddb107db2177b29#c03a2d8610cd27a9decb91b3bddb107db2177b29" +dependencies = [ + "aurora-engine-types", + "base64 0.21.7", + "sha2 0.10.8", + "sha3", +] + +[[package]] +name = "aurora-engine-transactions" +version = "1.0.0" +source = "git+https://github.com/aurora-is-near/aurora-engine.git?rev=c03a2d8610cd27a9decb91b3bddb107db2177b29#c03a2d8610cd27a9decb91b3bddb107db2177b29" +dependencies = [ + "aurora-engine-precompiles", + "aurora-engine-sdk", + "aurora-engine-types", + "evm", + "rlp", +] + +[[package]] +name = "aurora-engine-types" +version = "1.0.0" +source = "git+https://github.com/aurora-is-near/aurora-engine.git?rev=c03a2d8610cd27a9decb91b3bddb107db2177b29#c03a2d8610cd27a9decb91b3bddb107db2177b29" +dependencies = [ + "base64 0.21.7", + "borsh 1.3.1", + "bs58 0.5.1", + "hex", + "primitive-types 0.12.2", + "rlp", + "serde", + "serde_json", +] + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "binary-install" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93bff426ff93f3610dd2b946f3eb8cb2d1285ca8682834d43be531a3f93db2ff" +dependencies = [ + "anyhow", + "dirs-next", + "flate2", + "fs2", + "hex", + "is_executable", + "siphasher", + "tar", + "ureq", + "zip 0.6.6", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" +dependencies = [ + "crypto-mac", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[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 = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive 0.9.3", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58b559fd6448c6e2fd0adb5720cd98a2506594cafa4737ff98c396f3e82f667" +dependencies = [ + "borsh-derive 1.3.1", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd" +dependencies = [ + "once_cell", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.53", + "syn_derive", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "brownstone" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030ea61398f34f1395ccbeb046fb68c87b631d1f34567fed0f0f11fa35d18d8d" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "sha2 0.10.8", + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" +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 = "c2-chacha" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27dae93fe7b1e0424dc57179ac396908c26b035a87234809f5c4dfd1b47dc80" +dependencies = [ + "cipher 0.2.5", + "ppv-lite86", +] + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-near" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f73eb01da3b6737778d2006645533e75563d1080c64bf714bfb88d3fb0ac09b" +dependencies = [ + "anyhow", + "atty", + "bs58 0.4.0", + "camino", + "cargo_metadata", + "clap 3.2.25", + "colored", + "env_logger", + "libloading", + "log", + "near-abi", + "rustc_version", + "schemars", + "serde_json", + "sha2 0.10.8", + "symbolic-debuginfo", + "zstd", +] + +[[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.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[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 = "chrono" +version = "0.4.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.4", +] + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +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 = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_derive 3.2.25", + "clap_lex 0.2.4", + "indexmap 1.9.3", + "once_cell", + "strsim 0.10.0", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap" +version = "4.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +dependencies = [ + "clap_builder", + "clap_derive 4.5.3", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex 0.7.0", + "strsim 0.11.0", +] + +[[package]] +name = "clap_derive" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +dependencies = [ + "heck 0.4.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "clap_derive" +version = "4.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[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", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "platforms", + "rand_core 0.6.4", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "darling" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 2.0.53", +] + +[[package]] +name = "darling_macro" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "debugid" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ee87af31d84ef885378aebca32be3d682b0e0dc119d5b4860a2c5bb5046730" +dependencies = [ + "uuid", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[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", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + +[[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", +] + +[[package]] +name = "dmsort" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0bc8fbe9441c17c9f46f75dfe27fa1ddb6c68a461ccaed0481419219d4f10d3" + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "easy-ext" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53aff6fdc1b181225acdcb5b14c47106726fd8e486707315b1b138baed68ee31" + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", + "sha2 0.10.8", + "subtle", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "elementtree" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6319c9433cf1e95c60c8533978bccf0614f27f03bb4e514253468eeeaa7fe3" +dependencies = [ + "string_cache", + "xml-rs", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[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 = "eth-address-registrar" +version = "0.1.0" +dependencies = [ + "hex", + "near-sdk", + "serde", +] + +[[package]] +name = "eth-wallet-contract" +version = "0.1.0" +dependencies = [ + "anyhow", + "aurora-engine-transactions", + "aurora-engine-types", + "base64 0.21.7", + "ethabi", + "hex", + "near-crypto 0.21.2", + "near-sdk", + "near-workspaces", + "once_cell", + "rlp", + "serde", + "serde_json", + "sha3", + "tokio", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "sha3", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash 0.8.0", + "impl-codec", + "impl-rlp", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89fb87a9e103f71b903b80b670200b54cc67a07578f070681f1fffb7396fb7" +dependencies = [ + "bytes", + "ethereum-types", + "hash-db", + "hash256-std-hasher", + "rlp", + "sha3", + "triehash", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash 0.8.0", + "impl-codec", + "impl-rlp", + "primitive-types 0.12.2", + "scale-info", + "uint", +] + +[[package]] +name = "evm" +version = "0.39.1" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.39.1#0334a09d6b6e83ff3a8da992e33f29ba95e0c9fe" +dependencies = [ + "auto_impl", + "ethereum", + "evm-core", + "evm-gasometer", + "evm-runtime", + "log", + "primitive-types 0.12.2", + "rlp", + "sha3", +] + +[[package]] +name = "evm-core" +version = "0.39.1" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.39.1#0334a09d6b6e83ff3a8da992e33f29ba95e0c9fe" +dependencies = [ + "primitive-types 0.12.2", +] + +[[package]] +name = "evm-gasometer" +version = "0.39.1" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.39.1#0334a09d6b6e83ff3a8da992e33f29ba95e0c9fe" +dependencies = [ + "evm-core", + "evm-runtime", + "primitive-types 0.12.2", +] + +[[package]] +name = "evm-runtime" +version = "0.39.1" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.39.1#0334a09d6b6e83ff3a8da992e33f29ba95e0c9fe" +dependencies = [ + "auto_impl", + "evm-core", + "primitive-types 0.12.2", + "sha3", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fiat-crypto" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382" + +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "windows-sys 0.52.0", +] + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +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", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[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 = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "goblin" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" +dependencies = [ + "log", + "plain", + "scroll 0.11.0", +] + +[[package]] +name = "h2" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.2.5", + "slab", + "tokio", + "tokio-util 0.7.10", + "tracing", +] + +[[package]] +name = "hash-db" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" + +[[package]] +name = "hash256-std-hasher" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fa0ae458eb99874f54c09f4f9174f8b45fb87e854536a4e608696247f0c23" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +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 = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[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.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indent_write" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cfe9645a18782869361d9c8732246be7b410ad4e919d3609ebabdac00ba12c3" + +[[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.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown 0.14.4", + "serde", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is_executable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d553b8abc8187beb7d663e34c065ac4570b273bc9511a50e940e99409c577" +dependencies = [ + "winapi", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "joinery" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72167d68f5fce3b8655487b8038691a3c9984ee769590f93f2a631f4ad64e4f5" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +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 = "json_comments" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dbbfed4e59ba9750e15ba154fdfd9329cee16ff3df539c2666b70f58cc32105" + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[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 1.0.0", + "winapi", +] + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.5.0", + "libc", + "redox_syscall", +] + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[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 = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[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 = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[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", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "near-abi" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "885db39b08518fa700b73fa2214e8adbbfba316ba82dd510f50519173eadaf73" +dependencies = [ + "borsh 0.9.3", + "schemars", + "semver", + "serde", +] + +[[package]] +name = "near-account-id" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35cbb989542587b47205e608324ddd391f0cee1c22b4b64ae49f458334b95907" +dependencies = [ + "borsh 1.3.1", + "serde", +] + +[[package]] +name = "near-chain-configs" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e5a8ace81c09d7eb165dffc1742358a021b2fa761f2160943305f83216003" +dependencies = [ + "anyhow", + "bytesize", + "chrono", + "derive_more", + "near-config-utils 0.20.1", + "near-crypto 0.20.1", + "near-parameters", + "near-primitives", + "num-rational 0.3.2", + "once_cell", + "serde", + "serde_json", + "sha2 0.10.8", + "smart-default", + "tracing", +] + +[[package]] +name = "near-config-utils" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1eaab1d545a9be7a55b6ef09f365c2017f93a03063547591d12c0c6d27e58" +dependencies = [ + "anyhow", + "json_comments", + "thiserror", + "tracing", +] + +[[package]] +name = "near-config-utils" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1c9ff519efa8c778d341fa34971dee93e8adf4e8ae51feaefaa63bdf7e496a" +dependencies = [ + "anyhow", + "json_comments", + "thiserror", + "tracing", +] + +[[package]] +name = "near-crypto" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2991d2912218a80ec0733ac87f84fa803accea105611eea209d4419271957667" +dependencies = [ + "blake2", + "borsh 1.3.1", + "bs58 0.4.0", + "c2-chacha", + "curve25519-dalek", + "derive_more", + "ed25519-dalek", + "hex", + "near-account-id", + "near-config-utils 0.20.1", + "near-stdx 0.20.1", + "once_cell", + "primitive-types 0.10.1", + "rand 0.7.3", + "secp256k1", + "serde", + "serde_json", + "subtle", + "thiserror", +] + +[[package]] +name = "near-crypto" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d927e95742aea981b9fd60996fbeba3b61e90acafd54c2c3c2a4ed40065ff03" +dependencies = [ + "blake2", + "borsh 1.3.1", + "bs58 0.4.0", + "c2-chacha", + "curve25519-dalek", + "derive_more", + "ed25519-dalek", + "hex", + "near-account-id", + "near-config-utils 0.21.2", + "near-stdx 0.21.2", + "once_cell", + "primitive-types 0.10.1", + "rand 0.7.3", + "secp256k1", + "serde", + "serde_json", + "subtle", + "thiserror", +] + +[[package]] +name = "near-fmt" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d998dfc1e04001608899b2498ad5a782c7d036b73769d510de21964db99286" +dependencies = [ + "near-primitives-core", +] + +[[package]] +name = "near-gas" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e75c875026229902d065e4435804497337b631ec69ba746b102954273e9ad1" +dependencies = [ + "borsh 1.3.1", + "schemars", + "serde", +] + +[[package]] +name = "near-jsonrpc-client" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18ad81e015f7aced8925d5b9ba3f369b36da9575c15812cfd0786bc1213284ca" +dependencies = [ + "borsh 1.3.1", + "lazy_static", + "log", + "near-chain-configs", + "near-crypto 0.20.1", + "near-jsonrpc-primitives", + "near-primitives", + "reqwest", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "near-jsonrpc-primitives" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0ce745e954ae776eef05957602e638ee9581106a3675946fb43c2fe7e38ef03" +dependencies = [ + "arbitrary", + "near-chain-configs", + "near-crypto 0.20.1", + "near-primitives", + "near-rpc-error-macro", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "near-o11y" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d20762631bc8253030013bbae9b5f0542691edc1aa6722f1e8141cc9b928ae5b" +dependencies = [ + "actix", + "base64 0.21.7", + "clap 4.5.3", + "near-crypto 0.20.1", + "near-fmt", + "near-primitives-core", + "once_cell", + "opentelemetry", + "opentelemetry-otlp", + "opentelemetry-semantic-conventions", + "prometheus", + "serde", + "serde_json", + "strum 0.24.1", + "thiserror", + "tokio", + "tracing", + "tracing-appender", + "tracing-opentelemetry", + "tracing-subscriber", +] + +[[package]] +name = "near-parameters" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f16a59b6c3e69b0585be951af6fe42a0ba86c0e207cb8c63badd19efd16680" +dependencies = [ + "assert_matches", + "borsh 1.3.1", + "enum-map", + "near-account-id", + "near-primitives-core", + "num-rational 0.3.2", + "serde", + "serde_repr", + "serde_yaml", + "strum 0.24.1", + "thiserror", +] + +[[package]] +name = "near-primitives" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0462b067732132babcc89d5577db3bfcb0a1bcfbaaed3f2db4c11cd033666314" +dependencies = [ + "arbitrary", + "base64 0.21.7", + "borsh 1.3.1", + "bytesize", + "cfg-if 1.0.0", + "chrono", + "derive_more", + "easy-ext", + "enum-map", + "hex", + "near-crypto 0.20.1", + "near-fmt", + "near-o11y", + "near-parameters", + "near-primitives-core", + "near-rpc-error-macro", + "near-stdx 0.20.1", + "near-vm-runner", + "num-rational 0.3.2", + "once_cell", + "primitive-types 0.10.1", + "rand 0.8.5", + "rand_chacha 0.3.1", + "reed-solomon-erasure", + "serde", + "serde_json", + "serde_with", + "serde_yaml", + "sha3", + "smart-default", + "strum 0.24.1", + "thiserror", + "time", + "tracing", +] + +[[package]] +name = "near-primitives-core" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8443eb718606f572c438be6321a097a8ebd69f8e48d953885b4f16601af88225" +dependencies = [ + "arbitrary", + "base64 0.21.7", + "borsh 1.3.1", + "bs58 0.4.0", + "derive_more", + "enum-map", + "near-account-id", + "num-rational 0.3.2", + "serde", + "serde_repr", + "serde_with", + "sha2 0.10.8", + "strum 0.24.1", + "thiserror", +] + +[[package]] +name = "near-rpc-error-core" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80fca203c51edd9595ec14db1d13359fb9ede32314990bf296b6c5c4502f6ab7" +dependencies = [ + "quote", + "serde", + "syn 2.0.53", +] + +[[package]] +name = "near-rpc-error-macro" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897a445de2102f6732c8a185d922f5e3bf7fd0a41243ce40854df2197237f799" +dependencies = [ + "fs2", + "near-rpc-error-core", + "serde", + "syn 2.0.53", +] + +[[package]] +name = "near-sandbox-utils" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2de216bb0152bfb64f59016d9e6a5b1ac56dd85f729e5fde08461571e2182c8f" +dependencies = [ + "anyhow", + "binary-install", + "chrono", + "fs2", + "home", + "tokio", +] + +[[package]] +name = "near-sdk" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5c2e7c9524308b1b301cca05d875de13b3b20dc8b92e71f3890b380372e4c88" +dependencies = [ + "base64 0.21.7", + "borsh 1.3.1", + "bs58 0.5.1", + "near-account-id", + "near-gas", + "near-sdk-macros", + "near-sys", + "near-token", + "once_cell", + "serde", + "serde_json", + "wee_alloc", +] + +[[package]] +name = "near-sdk-macros" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e9b23d9d7757ade258921c9cbc7923542e64d9d3b52a6cd91f746c77cb0a0f" +dependencies = [ + "Inflector", + "darling", + "proc-macro2", + "quote", + "serde", + "serde_json", + "strum 0.26.2", + "strum_macros 0.26.2", + "syn 2.0.53", +] + +[[package]] +name = "near-stdx" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "855fd5540e3b4ff6fedf12aba2db1ee4b371b36f465da1363a6d022b27cb43b8" + +[[package]] +name = "near-stdx" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73a697f311c110d0fabae6c8c49ab0a8eff0ec37df82cc860deba92156e77c43" + +[[package]] +name = "near-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397688591acf8d3ebf2c2485ba32d4b24fc10aad5334e3ad8ec0b7179bfdf06b" + +[[package]] +name = "near-token" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b68f3f8a2409f72b43efdbeff8e820b81e70824c49fee8572979d789d1683fb" +dependencies = [ + "borsh 1.3.1", + "serde", +] + +[[package]] +name = "near-vm-runner" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56c80bdb1954808f59bd36a9112377197b38d424991383bf05f52d0fe2e0da5" +dependencies = [ + "base64 0.21.7", + "borsh 1.3.1", + "ed25519-dalek", + "enum-map", + "memoffset", + "near-crypto 0.20.1", + "near-parameters", + "near-primitives-core", + "near-stdx 0.20.1", + "num-rational 0.3.2", + "once_cell", + "prefix-sum-vec", + "ripemd", + "serde", + "serde_repr", + "serde_with", + "sha2 0.10.8", + "sha3", + "strum 0.24.1", + "thiserror", + "tracing", + "zeropool-bn", +] + +[[package]] +name = "near-workspaces" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e597da87d0c1a722e23efb8c24ae42a0ad99a15f37101dad45c15defb051c1" +dependencies = [ + "async-trait", + "base64 0.21.7", + "bs58 0.5.1", + "cargo-near", + "chrono", + "fs2", + "json-patch", + "libc", + "near-account-id", + "near-crypto 0.20.1", + "near-gas", + "near-jsonrpc-client", + "near-jsonrpc-primitives", + "near-primitives", + "near-sandbox-utils", + "near-token", + "rand 0.8.5", + "reqwest", + "serde", + "serde_json", + "sha2 0.10.8", + "tempfile", + "thiserror", + "tokio", + "tokio-retry", + "tracing", + "url", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[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 = "nom-supreme" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aadc66631948f6b65da03be4c4cd8bd104d481697ecbb9bbd65719b1ec60bc9f" +dependencies = [ + "brownstone", + "indent_write", + "joinery", + "memchr", + "nom", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint 0.4.4", + "num-complex", + "num-integer", + "num-iter", + "num-rational 0.4.1", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +dependencies = [ + "autocfg", + "num-integer", + "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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-bigint 0.3.3", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint 0.4.4", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +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 0.3.9", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags 2.5.0", + "cfg-if 1.0.0", + "foreign-types", + "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", + "syn 2.0.53", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "opentelemetry" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" +dependencies = [ + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "js-sys", + "lazy_static", + "percent-encoding", + "pin-project", + "rand 0.8.5", + "thiserror", + "tokio", + "tokio-stream", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1a6ca9de4c8b00aa7f1a153bd76cb263287155cec642680d79d98706f3d28a" +dependencies = [ + "async-trait", + "futures", + "futures-util", + "http", + "opentelemetry", + "prost", + "thiserror", + "tokio", + "tonic", + "tonic-build", +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985cc35d832d412224b2cffe2f9194b1b89b6aa5d0bef76d080dce09d90e62bd" +dependencies = [ + "opentelemetry", +] + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "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 = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", + "password-hash", + "sha2 0.10.8", +] + +[[package]] +name = "pdb" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13f4d162ecaaa1467de5afbe62d597757b674b51da8bb4e587430c5fdb2af7aa" +dependencies = [ + "fallible-iterator", + "scroll 0.10.2", + "uuid", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap 2.2.5", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[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.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "platforms" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.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 = "prefix-sum-vec" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa06bd51638b6e76ac9ba9b6afb4164fa647bd2916d722f2623fbb6d1ed8bdba" + +[[package]] +name = "primitive-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +dependencies = [ + "fixed-hash 0.7.0", + "uint", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash 0.8.0", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[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.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[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", + "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", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prometheus" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +dependencies = [ + "cfg-if 1.0.0", + "fnv", + "lazy_static", + "memchr", + "parking_lot", + "protobuf", + "thiserror", +] + +[[package]] +name = "prost" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" +dependencies = [ + "bytes", + "heck 0.3.3", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prost", + "prost-types", + "regex", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" +dependencies = [ + "bytes", + "prost", +] + +[[package]] +name = "protobuf" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[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", +] + +[[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.12", +] + +[[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 = "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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom 0.2.12", + "libredox", + "thiserror", +] + +[[package]] +name = "reed-solomon-erasure" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a415a013dd7c5d4221382329a5a3482566da675737494935cbbbcdec04662f9d" +dependencies = [ + "smallvec", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.6", + "regex-syntax 0.8.2", +] + +[[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.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[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.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "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", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if 1.0.0", + "getrandom 0.2.12", + "libc", + "spin 0.9.8", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[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.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pki-types" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ede67b28608b4c60685c7d54122d4400d90f62b40caee7700e700380a390fa8" + +[[package]] +name = "rustls-webpki" +version = "0.102.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +dependencies = [ + "ring", + "rustls-pki-types", + "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.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "scale-info" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef2175c2907e7c8bc0a9c3f86aeb5ec1f3b275300ad58a44d0c3ae379a5e52e" +dependencies = [ + "cfg-if 1.0.0", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b8eb8fd61c5cdd3390d9b2132300a7e7618955b98b8416f118c1b4e144f" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scroll" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" + +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "rand 0.8.5", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + +[[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", +] + +[[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 = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[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", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" +dependencies = [ + "base64 0.21.7", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.2.5", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "serde_yaml" +version = "0.9.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" +dependencies = [ + "indexmap 2.2.5", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[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 = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[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.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "smart-default" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[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", + "precomputed-hash", + "serde", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros 0.24.3", +] + +[[package]] +name = "strum" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "strum_macros" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.53", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "symbolic-common" +version = "8.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f551f902d5642e58039aee6a9021a61037926af96e071816361644983966f540" +dependencies = [ + "debugid", + "memmap2", + "stable_deref_trait", + "uuid", +] + +[[package]] +name = "symbolic-debuginfo" +version = "8.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165dabf9fc1d6bb6819c2c0e27c8dd0e3068d2c53cf186d319788e96517f0d6" +dependencies = [ + "bitvec", + "dmsort", + "elementtree", + "fallible-iterator", + "flate2", + "gimli 0.26.2", + "goblin", + "lazy_static", + "lazycell", + "nom", + "nom-supreme", + "parking_lot", + "pdb", + "regex", + "scroll 0.11.0", + "serde", + "serde_json", + "smallvec", + "symbolic-common", + "thiserror", + "wasmparser", + "zip 0.5.13", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[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 = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[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.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[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-retry" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" +dependencies = [ + "pin-project", + "rand 0.8.5", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.2.5", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.2.5", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.5", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tonic" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a" +dependencies = [ + "async-stream", + "async-trait", + "base64 0.13.1", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "prost-derive", + "tokio", + "tokio-stream", + "tokio-util 0.6.10", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tonic-build" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9403f1bafde247186684b230dc6f38b5cd514584e8bec1dd32514be4745fa757" +dependencies = [ + "proc-macro2", + "prost-build", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util 0.7.10", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[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.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror", + "time", + "tracing-subscriber", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-log" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-opentelemetry" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbbe89715c1dbbb790059e2565353978564924ee85017b5fff365c872ff6721f" +dependencies = [ + "once_cell", + "opentelemetry", + "tracing", + "tracing-core", + "tracing-log 0.1.4", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log 0.2.0", +] + +[[package]] +name = "treediff" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d127780145176e2b5d16611cc25a900150e86e9fd79d3bde6ff3a37359c9cb5" +dependencies = [ + "serde_json", +] + +[[package]] +name = "triehash" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1631b201eb031b563d2e85ca18ec8092508e262a3196ce9bd10a67ec87b9f5c" +dependencies = [ + "hash-db", + "rlp", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" +dependencies = [ + "base64 0.21.7", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "rustls-webpki", + "url", + "webpki-roots", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + +[[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_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[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.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.53", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasmparser" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "memory_units", + "winapi", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.4", +] + +[[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.4", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if 1.0.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zeropool-bn" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e61de68ede9ffdd69c01664f65a178c5188b73f78faa21f0936016a888ff7c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand 0.8.5", + "rustc-hex", +] + +[[package]] +name = "zip" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" +dependencies = [ + "byteorder", + "crc32fast", + "flate2", + "thiserror", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac 0.12.1", + "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", +] diff --git a/runtime/near-wallet-contract/implementation/Cargo.toml b/runtime/near-wallet-contract/implementation/Cargo.toml new file mode 100644 index 00000000000..70ef37a20d6 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/Cargo.toml @@ -0,0 +1,37 @@ +[workspace.package] +authors = ["Aurora Labs "] +version = "0.1.0" +edition = "2021" +homepage = "https://github.com/aurora-is-near/eth-wallet-contract" +repository = "https://github.com/aurora-is-near/eth-wallet-contract" +license = "CC0-1.0" + + +[workspace.dependencies] +aurora-engine-transactions = { git = "https://github.com/aurora-is-near/aurora-engine.git", rev = "c03a2d8610cd27a9decb91b3bddb107db2177b29", default-features = false, features = ["contract"]} +base64 = "0.21" +ethabi = { version = "18", default-features = false } +hex = "0.4" +near-sdk = { version = "5.0" } +once_cell = "1.18" +serde = { version = "1", features = ["derive"] } + +# dev-dependencies +anyhow = "1" +aurora-engine-types = { git = "https://github.com/aurora-is-near/aurora-engine.git", rev = "c03a2d8610cd27a9decb91b3bddb107db2177b29", default-features = false } +near-crypto = "0.21" +near-workspaces = "0.10" +rlp = { version = "0.5", default-features = false } +serde_json = "1" +sha3 = "0.10" +tokio = { version = "1", features = ["full"] } + +[workspace] +resolver = "2" +members = [ + "address-registrar", + "wallet-contract", +] + +[profile.release] +panic = 'abort' diff --git a/runtime/near-wallet-contract/implementation/address-registrar/Cargo.toml b/runtime/near-wallet-contract/implementation/address-registrar/Cargo.toml new file mode 100644 index 00000000000..bdc768e8431 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/address-registrar/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "eth-address-registrar" +version.workspace = true +edition.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +hex.workspace = true +near-sdk.workspace = true +serde.workspace = true diff --git a/runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs b/runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs new file mode 100644 index 00000000000..59fe2631ca1 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs @@ -0,0 +1,76 @@ +use near_sdk::{ + borsh::{BorshDeserialize, BorshSerialize}, + env, near_bindgen, + store::{lookup_map::Entry, LookupMap}, + AccountId, BorshStorageKey, PanicOnDefault, +}; + +type Address = [u8; 20]; + +#[derive(BorshSerialize, BorshStorageKey)] +#[borsh(crate = "near_sdk::borsh")] +enum StorageKey { + Addresses, +} + +#[near_bindgen] +#[derive(PanicOnDefault, BorshDeserialize, BorshSerialize)] +#[borsh(crate = "near_sdk::borsh")] +pub struct AddressRegistrar { + pub addresses: LookupMap, +} + +#[near_bindgen] +impl AddressRegistrar { + #[init] + pub fn new() -> Self { + Self { + addresses: LookupMap::new(StorageKey::Addresses), + } + } + + pub fn register(&mut self, account_id: AccountId) -> Option { + let address = account_id_to_address(&account_id); + + match self.addresses.entry(address) { + Entry::Vacant(entry) => { + let address = format!("0x{}", hex::encode(address)); + let log_message = format!("Added entry {} -> {}", address, account_id); + entry.insert(account_id); + env::log_str(&log_message); + Some(address) + } + Entry::Occupied(entry) => { + let log_message = format!( + "Address collision between {} and {}. Keeping the former.", + entry.get(), + account_id + ); + env::log_str(&log_message); + None + } + } + } + + pub fn lookup(&self, address: String) -> Option { + let address = { + let mut buf = [0u8; 20]; + hex::decode_to_slice(address.strip_prefix("0x").unwrap_or(&address), &mut buf) + .unwrap_or_else(|_| env::panic_str("Invalid hex encoding")); + buf + }; + self.addresses.get(&address).cloned() + } + + pub fn get_address(&self, account_id: AccountId) -> String { + let address = account_id_to_address(&account_id); + format!("0x{}", hex::encode(address)) + } +} + +fn account_id_to_address(account_id: &AccountId) -> Address { + let hash = near_sdk::env::keccak256_array(account_id.as_bytes()); + let mut result = [0u8; 20]; + result.copy_from_slice(&hash[12..32]); + result +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/Cargo.toml b/runtime/near-wallet-contract/implementation/wallet-contract/Cargo.toml new file mode 100644 index 00000000000..fc8e36dbd84 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "eth-wallet-contract" +version.workspace = true +edition.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +aurora-engine-transactions.workspace = true +base64.workspace = true +ethabi.workspace = true +hex.workspace = true +near-sdk.workspace = true +once_cell.workspace = true +serde.workspace = true +serde_json.workspace = true + +[dev-dependencies] +anyhow.workspace = true +aurora-engine-types.workspace = true +near-crypto.workspace = true +near-workspaces.workspace = true +rlp.workspace = true +sha3.workspace = true +tokio.workspace = true diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/ADDRESS_REGISTRAR_ACCOUNT_ID b/runtime/near-wallet-contract/implementation/wallet-contract/src/ADDRESS_REGISTRAR_ACCOUNT_ID new file mode 100644 index 00000000000..258cd5725da --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/ADDRESS_REGISTRAR_ACCOUNT_ID @@ -0,0 +1 @@ +todo diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/error.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/error.rs new file mode 100644 index 00000000000..17aa61f8325 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/error.rs @@ -0,0 +1,167 @@ +use std::fmt; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Error { + AccountNonceExhausted, + AccountId(AccountIdError), + Relayer(RelayerError), + User(UserError), + Caller(CallerError), +} + +/// Errors that should never happen when the Eth Implicit accounts feature +/// is available on Near. These errors relate to parsing a 20-byte address +/// from a Near account ID. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum AccountIdError { + AccountIdTooShort, + Missing0xPrefix, + InvalidHex, +} + +/// Errors which should never happen if the relayer is honest. +/// If these errors happen then we should ban the relayer (revoke their access key). +/// An external caller (as opposed to a relayer with a Function Call access key) may +/// also trigger these errors by passing bad arguments, but this is not an issue +/// (there is no ban list for external callers) because they are paying the gas fees +/// for their own mistakes. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum RelayerError { + /// Relayers should always check the nonce before sending + InvalidNonce, + /// Relayers should always encode the transaction correctly + InvalidBase64, + /// Relayers should always send valid transactions + TxParsing(aurora_engine_transactions::Error), + /// Relayers should always send correctly signed transactions + InvalidSender, + /// Relayers should always give the correct target account + InvalidTarget, + /// Relayers should always check the transaction is signed with the correct chain id. + InvalidChainId, +} + +/// Errors that arise from problems in the data signed by the user +/// (i.e. in the Ethereum transaction itself). A careful power-user +/// should never see these errors because they can review the data +/// they are signing. If a user does see these errors then there is +/// likely a bug in the front-end code that is constructing the Ethereum +/// transaction to be signed. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum UserError { + EvmDeployDisallowed, + ValueTooLarge, + UnknownPublicKeyKind, + InvalidEd25519Key, + InvalidSecp256k1Key, + InvalidAccessKeyAccountId, + UnsupportedAction(UnsupportedAction), + UnknownFunctionSelector, + InvalidAbiEncodedData, + ExcessYoctoNear, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum UnsupportedAction { + AddFullAccessKey, + CreateAccount, + Delegate, + DeleteAccount, + DeployContract, + Stake, +} + +/// Errors that arise from external accounts calling the Wallet Contract. +/// The `rlp_execute` function is intentionally public so that any account +/// can pay for the fees on behalf of a Wallet Contract key holder. +/// These errors are not a big deal from the perspective of the Wallet Contract +/// because the cost for executing such erroneous transactions are paid for +/// by that external caller. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum CallerError { + InsufficientAttachedValue, +} + +impl From for Error { + fn from(value: aurora_engine_transactions::Error) -> Self { + Self::Relayer(RelayerError::TxParsing(value)) + } +} + +impl fmt::Display for AccountIdError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::AccountIdTooShort => f.write_str("Error: account ID too short"), + Self::Missing0xPrefix => f.write_str("Error: account ID missing 0x"), + Self::InvalidHex => f.write_str("Error: account ID is not valid hex encoding"), + } + } +} + +impl fmt::Display for RelayerError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::TxParsing(e) => std::write!(f, "Error parsing RLP {}", e.as_str()), + Self::InvalidSender => f.write_str("Error: signature is not from account owner"), + Self::InvalidBase64 => f.write_str("Error: invalid base64 encoding"), + Self::InvalidTarget => { + f.write_str("Error: target does not match to in signed transaction") + } + Self::InvalidNonce => f.write_str("Error: invalid nonce value"), + Self::InvalidChainId => f.write_str("Error: invalid chain id value"), + } + } +} + +impl fmt::Display for UserError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::EvmDeployDisallowed => { + f.write_str("Error: transactions deploying EVM contracts not allowed") + } + Self::ValueTooLarge => { + f.write_str("Error: transaction value must be representable by 128 bits") + } + Self::UnknownPublicKeyKind => f.write_str("Error: unknown public key kind"), + Self::InvalidEd25519Key => f.write_str("Error: invalid ED25519 public key"), + Self::InvalidSecp256k1Key => f.write_str("Error: invalid SECP256k1 public key"), + Self::InvalidAccessKeyAccountId => f.write_str( + "Error: attempt to add function call access key with invalid account id", + ), + Self::UnsupportedAction(a) => { + std::write!(f, "Error unsupported action {:?}", a) + } + Self::UnknownFunctionSelector => f.write_str("Error: unknown function selector"), + Self::InvalidAbiEncodedData => { + f.write_str("Error: invalid ABI encoding in transaction data") + } + Self::ExcessYoctoNear => f.write_str( + "Error: only at most 1_000_000 yoctoNear can be included directly in an action", + ), + } + } +} + +impl fmt::Display for CallerError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InsufficientAttachedValue => { + f.write_str("Error: external calls must attach Near to pay for their transactions") + } + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::AccountNonceExhausted => f.write_str("Error: no nonce values remain"), + Self::AccountId(e) => e.fmt(f), + Self::Relayer(e) => e.fmt(f), + Self::User(e) => e.fmt(f), + Self::Caller(e) => e.fmt(f), + } + } +} + +impl std::error::Error for Error {} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs new file mode 100644 index 00000000000..f1c6137a724 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs @@ -0,0 +1,87 @@ +//! This module contains logic for emulating Ethereum standards with the +//! corresponding Near actions. For now only the ERC-20 standard is supported +//! (which corresponds to Near's NEP-141). + +use crate::{ + error::{Error, UserError}, + ethabi_utils, + types::{Action, ExecutionContext}, +}; +use aurora_engine_transactions::NormalizedEthTransaction; +use ethabi::{Address, ParamType}; +use near_sdk::AccountId; + +const FIVE_TERA_GAS: u64 = near_sdk::Gas::from_tgas(5).as_gas(); + +pub const ERC20_BALANCE_OF_SELECTOR: &[u8] = &[0x70, 0xa0, 0x82, 0x31]; +const ERC20_BALANCE_OF_SIGNATURE: [ParamType; 1] = [ParamType::Address]; + +pub const ERC20_TRANSFER_SELECTOR: &[u8] = &[0xa9, 0x05, 0x9c, 0xbb]; +const ERC20_TRANSFER_SIGNATURE: [ParamType; 2] = [ + ParamType::Address, // to + ParamType::Uint(256), // value +]; + +pub fn try_emulation( + target: &AccountId, + tx: &NormalizedEthTransaction, + context: &ExecutionContext, +) -> Result { + if tx.data.len() < 4 { + return Err(Error::User(UserError::InvalidAbiEncodedData)); + } + let suffix = context + .current_account_id + .as_str() + .find('.') + .map(|index| &context.current_account_id.as_str()[index..]) + .unwrap_or(""); + match &tx.data[0..4] { + ERC20_BALANCE_OF_SELECTOR => { + let (address,): (Address,) = + ethabi_utils::abi_decode(&ERC20_BALANCE_OF_SIGNATURE, &tx.data[4..])?; + let args = format!( + r#"{{"account_id": "0x{}{}"}}"#, + hex::encode(address), + suffix + ); + Ok(Action::FunctionCall { + receiver_id: target.to_string(), + method_name: "ft_balance_of".into(), + args: args.into_bytes(), + gas: FIVE_TERA_GAS, + yocto_near: 0, + }) + } + ERC20_TRANSFER_SELECTOR => { + // We intentionally map to `u128` instead of `U256` because the NEP-141 standard + // is to use u128. + let (to, value): (Address, u128) = + ethabi_utils::abi_decode(&ERC20_TRANSFER_SIGNATURE, &tx.data[4..])?; + let args = format!( + r#"{{"receiver_id": "0x{}{}", "amount": "{}", "memo": null}}"#, + hex::encode(to), + suffix, + value + ); + Ok(Action::FunctionCall { + receiver_id: target.to_string(), + method_name: "ft_transfer".into(), + args: args.into_bytes(), + gas: 2 * FIVE_TERA_GAS, + yocto_near: 1, + }) + } + _ => Err(Error::User(UserError::UnknownFunctionSelector)), + } +} + +#[test] +fn test_function_selectors() { + let balance_of_signature = ethabi::short_signature("balanceOf", &ERC20_BALANCE_OF_SIGNATURE); + + let transfer_signature = ethabi::short_signature("transfer", &ERC20_TRANSFER_SIGNATURE); + + assert_eq!(balance_of_signature, ERC20_BALANCE_OF_SELECTOR); // 0x70a08231 + assert_eq!(transfer_signature, ERC20_TRANSFER_SELECTOR); // 0xa9059cbb +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/ethabi_utils.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/ethabi_utils.rs new file mode 100644 index 00000000000..73746a07b0c --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/ethabi_utils.rs @@ -0,0 +1,254 @@ +use crate::error::{Error, UserError}; +use ethabi::{ethereum_types::U256, Address, ParamType, Token}; + +const INVALID_ABI_DATA: Error = Error::User(UserError::InvalidAbiEncodedData); + +pub fn abi_decode(types: &[ParamType; N], data: &[u8]) -> Result +where + T: AbiTuple, +{ + let tokens = data_to_tokens(types, data)?; + T::try_from_token(tokens) +} + +pub trait AbiTuple: Sized { + fn try_from_token(tokens: [Token; N]) -> Result; +} + +impl AbiTuple<1> for (T,) +where + T: TryFromToken, +{ + fn try_from_token(tokens: [Token; 1]) -> Result { + let (t,) = tokens.into(); + T::try_from_token(t).map(|t| (t,)) + } +} + +impl AbiTuple<2> for (T1, T2) +where + T1: TryFromToken, + T2: TryFromToken, +{ + fn try_from_token(tokens: [Token; 2]) -> Result { + let (t1, t2) = tokens.into(); + Ok((T1::try_from_token(t1)?, T2::try_from_token(t2)?)) + } +} + +impl AbiTuple<3> for (T1, T2, T3) +where + T1: TryFromToken, + T2: TryFromToken, + T3: TryFromToken, +{ + fn try_from_token(tokens: [Token; 3]) -> Result { + let (t1, t2, t3) = tokens.into(); + Ok(( + T1::try_from_token(t1)?, + T2::try_from_token(t2)?, + T3::try_from_token(t3)?, + )) + } +} + +impl AbiTuple<4> for (T1, T2, T3, T4) +where + T1: TryFromToken, + T2: TryFromToken, + T3: TryFromToken, + T4: TryFromToken, +{ + fn try_from_token(tokens: [Token; 4]) -> Result { + let (t1, t2, t3, t4) = tokens.into(); + Ok(( + T1::try_from_token(t1)?, + T2::try_from_token(t2)?, + T3::try_from_token(t3)?, + T4::try_from_token(t4)?, + )) + } +} + +impl AbiTuple<5> for (T1, T2, T3, T4, T5) +where + T1: TryFromToken, + T2: TryFromToken, + T3: TryFromToken, + T4: TryFromToken, + T5: TryFromToken, +{ + fn try_from_token(tokens: [Token; 5]) -> Result { + let (t1, t2, t3, t4, t5) = tokens.into(); + Ok(( + T1::try_from_token(t1)?, + T2::try_from_token(t2)?, + T3::try_from_token(t3)?, + T4::try_from_token(t4)?, + T5::try_from_token(t5)?, + )) + } +} + +impl AbiTuple<6> for (T1, T2, T3, T4, T5, T6) +where + T1: TryFromToken, + T2: TryFromToken, + T3: TryFromToken, + T4: TryFromToken, + T5: TryFromToken, + T6: TryFromToken, +{ + fn try_from_token(tokens: [Token; 6]) -> Result { + let (t1, t2, t3, t4, t5, t6) = tokens.into(); + Ok(( + T1::try_from_token(t1)?, + T2::try_from_token(t2)?, + T3::try_from_token(t3)?, + T4::try_from_token(t4)?, + T5::try_from_token(t5)?, + T6::try_from_token(t6)?, + )) + } +} + +impl AbiTuple<7> for (T1, T2, T3, T4, T5, T6, T7) +where + T1: TryFromToken, + T2: TryFromToken, + T3: TryFromToken, + T4: TryFromToken, + T5: TryFromToken, + T6: TryFromToken, + T7: TryFromToken, +{ + fn try_from_token(tokens: [Token; 7]) -> Result { + let (t1, t2, t3, t4, t5, t6, t7) = tokens.into(); + Ok(( + T1::try_from_token(t1)?, + T2::try_from_token(t2)?, + T3::try_from_token(t3)?, + T4::try_from_token(t4)?, + T5::try_from_token(t5)?, + T6::try_from_token(t6)?, + T7::try_from_token(t7)?, + )) + } +} + +impl AbiTuple<8> for (T1, T2, T3, T4, T5, T6, T7, T8) +where + T1: TryFromToken, + T2: TryFromToken, + T3: TryFromToken, + T4: TryFromToken, + T5: TryFromToken, + T6: TryFromToken, + T7: TryFromToken, + T8: TryFromToken, +{ + fn try_from_token(tokens: [Token; 8]) -> Result { + let (t1, t2, t3, t4, t5, t6, t7, t8) = tokens.into(); + Ok(( + T1::try_from_token(t1)?, + T2::try_from_token(t2)?, + T3::try_from_token(t3)?, + T4::try_from_token(t4)?, + T5::try_from_token(t5)?, + T6::try_from_token(t6)?, + T7::try_from_token(t7)?, + T8::try_from_token(t8)?, + )) + } +} + +trait TryFromToken: Sized { + fn try_from_token(t: Token) -> Result; +} + +impl TryFromToken for u8 { + fn try_from_token(t: Token) -> Result { + const U8_MAX: U256 = U256([u8::MAX as u64, 0, 0, 0]); + let x = t.into_uint().ok_or(INVALID_ABI_DATA)?; + if x <= U8_MAX { + Ok(x.low_u32() as u8) + } else { + Err(INVALID_ABI_DATA) + } + } +} + +impl TryFromToken for u32 { + fn try_from_token(t: Token) -> Result { + const U32_MAX: U256 = U256([u32::MAX as u64, 0, 0, 0]); + let x = t.into_uint().ok_or(INVALID_ABI_DATA)?; + if x <= U32_MAX { + Ok(x.low_u32()) + } else { + Err(INVALID_ABI_DATA) + } + } +} + +impl TryFromToken for u64 { + fn try_from_token(t: Token) -> Result { + const U64_MAX: U256 = U256([u64::MAX, 0, 0, 0]); + let x = t.into_uint().ok_or(INVALID_ABI_DATA)?; + if x <= U64_MAX { + Ok(x.low_u64()) + } else { + Err(INVALID_ABI_DATA) + } + } +} + +impl TryFromToken for u128 { + fn try_from_token(t: Token) -> Result { + const U128_MAX: U256 = U256([u64::MAX, u64::MAX, 0, 0]); + let x = t.into_uint().ok_or(INVALID_ABI_DATA)?; + if x <= U128_MAX { + Ok(x.low_u128()) + } else { + Err(INVALID_ABI_DATA) + } + } +} + +impl TryFromToken for bool { + fn try_from_token(t: Token) -> Result { + t.into_bool().ok_or(INVALID_ABI_DATA) + } +} + +impl TryFromToken for String { + fn try_from_token(t: Token) -> Result { + t.into_string().ok_or(INVALID_ABI_DATA) + } +} + +impl TryFromToken for Address { + fn try_from_token(t: Token) -> Result { + t.into_address().ok_or(INVALID_ABI_DATA) + } +} + +impl TryFromToken for Vec { + fn try_from_token(t: Token) -> Result { + t.into_bytes().ok_or(INVALID_ABI_DATA) + } +} + +impl TryFromToken for Vec { + fn try_from_token(t: Token) -> Result { + let elems = t.into_array().ok_or(INVALID_ABI_DATA)?; + elems.into_iter().map(String::try_from_token).collect() + } +} + +fn data_to_tokens( + types: &[ParamType; N], + data: &[u8], +) -> Result<[ethabi::Token; N], Error> { + let result = ethabi::decode(types.as_slice(), data).map_err(|_| INVALID_ABI_DATA)?; + result.try_into().map_err(|_| INVALID_ABI_DATA) +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs new file mode 100644 index 00000000000..714cfc8e59b --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs @@ -0,0 +1,286 @@ +use crate::{ + error::{AccountIdError, CallerError, Error, RelayerError, UserError}, + eth_emulation, ethabi_utils, near_action, + types::{ + Action, ExecutionContext, TransactionValidationOutcome, ADD_KEY_SELECTOR, + ADD_KEY_SIGNATURE, DELETE_KEY_SELECTOR, DELETE_KEY_SIGNATURE, FUNCTION_CALL_SELECTOR, + FUNCTION_CALL_SIGNATURE, TRANSFER_SELECTOR, TRANSFER_SIGNATURE, + }, +}; +use aurora_engine_transactions::{EthTransactionKind, NormalizedEthTransaction}; +use base64::Engine; +use ethabi::{ethereum_types::U256, Address}; +use near_sdk::{AccountId, NearToken}; + +// TODO: Decide on chain id. +pub const CHAIN_ID: u64 = 0x4ea7; +const U64_MAX: U256 = U256([u64::MAX, 0, 0, 0]); +/// Only up to this amount of yoctoNear can be directly mentioned in an action, +/// the rest should be included in the `value` field of the Ethereum transaction. +pub const MAX_YOCTO_NEAR: u32 = 1_000_000; + +/// The largest accepted `value` field of a transaction. +/// Computed as `(2**128 - 1) // 1_000_000` since Near balances are +/// 128-bit numbers, but with 24 decimals instead of 18. So to covert +/// an Ethereum transaction value into a Near value we need to multiply +/// by `1_000_000` and then add back any lower digits that were truncated. +const VALUE_MAX: U256 = U256([10175519178963368024, 18446744073709, 0, 0]); + +/// Given an RLP-encoded Ethereum transaction (bytes encoded in base64), +/// a Near account the transaction is supposed to interact with, the current +/// account ID, and the current nonce, this function will attempt to transform +/// the Ethereum transaction into a Near action. +pub fn parse_rlp_tx_to_action( + tx_bytes_b64: &str, + target: &AccountId, + context: &ExecutionContext, + expected_nonce: &mut u64, +) -> Result<(near_action::Action, TransactionValidationOutcome), Error> { + let tx_bytes = decode_b64(tx_bytes_b64)?; + let tx_kind: EthTransactionKind = tx_bytes.as_slice().try_into()?; + let tx: NormalizedEthTransaction = tx_kind.try_into()?; + let validation_outcome = validate_tx_relayer_data(&tx, target, context, *expected_nonce)?; + + // If the transaction is valid then increment the nonce to prevent replay + *expected_nonce = expected_nonce.saturating_add(1); + + let to = tx + .to + .ok_or(Error::User(UserError::EvmDeployDisallowed))? + .raw(); + let action = if to != context.current_address + && extract_address(target).map(|a| a == to).unwrap_or(false) + { + // If target is another Ethereum implicit account then the action + // must be a transfer (because EOAs are not contracts on Ethereum). + Action::Transfer { + receiver_id: target.to_string(), + yocto_near: 0, + } + } else { + parse_tx_data(target, &tx, context)? + }; + validate_tx_value(&tx, context, &action)?; + + // Call to `low_u128` here is safe because of the validation done in `validate_tx_value` + let near_action = action.try_into_near_action( + tx.value + .raw() + .low_u128() + .saturating_mul(MAX_YOCTO_NEAR.into()), + )?; + + Ok((near_action, validation_outcome)) +} + +/// Extracts a 20-byte address from a Near account ID. +/// This is done by assuming the account ID is of the form `^0x[0-9a-f]{40}`, +/// i.e. it starts with `0x` and then hex-encoded 20 bytes. +pub fn extract_address(current_account_id: &AccountId) -> Result { + let hex_str = current_account_id.as_bytes(); + + // TODO: in production be strict about account ID is exactly 42 bytes. + if hex_str.len() < 42 { + return Err(Error::AccountId(AccountIdError::AccountIdTooShort)); + } + + if &hex_str[0..2] != b"0x" { + return Err(Error::AccountId(AccountIdError::Missing0xPrefix)); + } + + let mut bytes = [0u8; 20]; + hex::decode_to_slice(&hex_str[2..42], &mut bytes) + .map_err(|_| Error::AccountId(AccountIdError::InvalidHex))?; + + Ok(bytes.into()) +} + +/// Decode a base-64 encoded string into raw bytes. +fn decode_b64(input: &str) -> Result, Error> { + let engine = base64::engine::general_purpose::STANDARD; + engine + .decode(input) + .map_err(|_| Error::Relayer(RelayerError::InvalidBase64)) +} + +/// Coverts any Near account ID into a 20-byte address by taking the last 20 bytes +/// of the keccak256 hash. +pub fn hash_to_address(account_id: &AccountId) -> Address { + let hash = keccak256(account_id.as_bytes()); + let mut result = [0u8; 20]; + result.copy_from_slice(&hash[12..32]); + result.into() +} + +pub fn keccak256(bytes: &[u8]) -> [u8; 32] { + #[cfg(test)] + { + use sha3::{Digest, Keccak256}; + let hash = Keccak256::digest(bytes); + hash.into() + } + + #[cfg(not(test))] + near_sdk::env::keccak256_array(bytes) +} + +fn parse_tx_data( + target: &AccountId, + tx: &NormalizedEthTransaction, + context: &ExecutionContext, +) -> Result { + if tx.data.len() < 4 { + return Err(Error::User(UserError::InvalidAbiEncodedData)); + } + match &tx.data[0..4] { + FUNCTION_CALL_SELECTOR => { + let (receiver_id, method_name, args, gas, yocto_near): (String, _, _, _, _) = + ethabi_utils::abi_decode(&FUNCTION_CALL_SIGNATURE, &tx.data[4..])?; + if target.as_str() != receiver_id.as_str() { + return Err(Error::Relayer(RelayerError::InvalidTarget)); + } + if yocto_near > MAX_YOCTO_NEAR { + return Err(Error::User(UserError::ExcessYoctoNear)); + } + Ok(Action::FunctionCall { + receiver_id, + method_name, + args, + gas, + yocto_near, + }) + } + TRANSFER_SELECTOR => { + let (receiver_id, yocto_near): (String, u32) = + ethabi_utils::abi_decode(&TRANSFER_SIGNATURE, &tx.data[4..])?; + if target.as_str() != receiver_id.as_str() { + return Err(Error::Relayer(RelayerError::InvalidTarget)); + } + if yocto_near > MAX_YOCTO_NEAR { + return Err(Error::User(UserError::ExcessYoctoNear)); + } + Ok(Action::Transfer { + receiver_id, + yocto_near, + }) + } + ADD_KEY_SELECTOR => { + let ( + public_key_kind, + public_key, + nonce, + is_full_access, + is_limited_allowance, + allowance, + receiver_id, + method_names, + ) = ethabi_utils::abi_decode(&ADD_KEY_SIGNATURE, &tx.data[4..])?; + Ok(Action::AddKey { + public_key_kind, + public_key, + nonce, + is_full_access, + is_limited_allowance, + allowance, + receiver_id, + method_names, + }) + } + DELETE_KEY_SELECTOR => { + let (public_key_kind, public_key) = + ethabi_utils::abi_decode(&DELETE_KEY_SIGNATURE, &tx.data[4..])?; + Ok(Action::DeleteKey { + public_key_kind, + public_key, + }) + } + _ => eth_emulation::try_emulation(target, tx, context), + } +} + +/// Validates the transaction is following the Wallet Contract protocol. +/// This includes checks for: +/// - from address matches current account address +/// - to address is present and matches the target address (or hash of target account ID) +/// - nonce matches expected nonce +/// If this validation fails then the relayer that sent it is faulty and should be banned. +fn validate_tx_relayer_data( + tx: &NormalizedEthTransaction, + target: &AccountId, + context: &ExecutionContext, + expected_nonce: u64, +) -> Result { + if tx.address.raw() != context.current_address { + return Err(Error::Relayer(RelayerError::InvalidSender)); + } + + if tx.chain_id != Some(CHAIN_ID) { + return Err(Error::Relayer(RelayerError::InvalidChainId)); + } + + let to = tx + .to + .ok_or(Error::User(UserError::EvmDeployDisallowed))? + .raw(); + let target_as_address = extract_address(target).ok(); + let to_equals_target = target_as_address + .map(|target| to == target) + .unwrap_or(false); + + // Only valid targets satisfy `to == target` or `to == hash(target)` + if !to_equals_target && to != hash_to_address(target) { + return Err(Error::Relayer(RelayerError::InvalidTarget)); + } + + let nonce = if tx.nonce <= U64_MAX { + tx.nonce.low_u64() + } else { + return Err(Error::Relayer(RelayerError::InvalidNonce)); + }; + if nonce != expected_nonce { + return Err(Error::Relayer(RelayerError::InvalidNonce)); + } + + // If `to == target` and this is not a self-transaction then the address must not + // be registered in the address registry. The purpose of this check is to prevent + // lazy relayers from skipping this check themselves (relayers are supposed to use + // the address registry to fill in the `target`). + if to_equals_target && to != context.current_address { + Ok(TransactionValidationOutcome::AddressCheckRequired(to)) + } else { + Ok(TransactionValidationOutcome::Validated) + } +} + +fn validate_tx_value( + tx: &NormalizedEthTransaction, + context: &ExecutionContext, + action: &Action, +) -> Result<(), Error> { + if tx.value.raw() > VALUE_MAX { + return Err(Error::User(UserError::ValueTooLarge)); + } + + let total_value = tx + .value + .raw() + .low_u128() + .saturating_mul(MAX_YOCTO_NEAR.into()) + .saturating_add(action.value().as_yoctonear()); + + if total_value > 0 { + let is_self_call = context.predecessor_account_id == context.current_account_id; + let sufficient_attached_deposit = + context.attached_deposit >= NearToken::from_yoctonear(total_value); + if !is_self_call && !sufficient_attached_deposit { + return Err(Error::Caller(CallerError::InsufficientAttachedValue)); + } + } + + Ok(()) +} + +#[test] +fn test_value_max() { + assert_eq!(VALUE_MAX, U256::from(u128::MAX / 1_000_000)); +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs new file mode 100644 index 00000000000..c7a86009c9c --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs @@ -0,0 +1,245 @@ +use crate::{ + error::Error, + types::{ExecuteResponse, ExecutionContext}, +}; +use error::{UnsupportedAction, UserError}; +use near_sdk::{ + borsh::{BorshDeserialize, BorshSerialize}, + env, + json_types::U64, + near_bindgen, AccountId, Allowance, Gas, GasWeight, NearToken, Promise, PromiseOrValue, + PromiseResult, +}; +use types::TransactionValidationOutcome; + +pub mod error; +pub mod eth_emulation; +pub mod ethabi_utils; +pub mod internal; +pub mod near_action; +pub mod types; + +#[cfg(test)] +mod tests; + +const ADDRESS_REGISTRAR_ACCOUNT_ID: &str = std::include_str!("ADDRESS_REGISTRAR_ACCOUNT_ID"); + +#[near_bindgen] +#[derive(Default, BorshDeserialize, BorshSerialize)] +#[borsh(crate = "near_sdk::borsh")] +pub struct WalletContract { + pub nonce: u64, +} + +#[near_bindgen] +impl WalletContract { + pub fn get_nonce(&self) -> U64 { + U64(self.nonce) + } + + #[payable] + pub fn rlp_execute( + &mut self, + target: AccountId, + tx_bytes_b64: String, + ) -> PromiseOrValue { + let current_account_id = env::current_account_id(); + let predecessor_account_id = env::predecessor_account_id(); + let result = inner_rlp_execute( + current_account_id.clone(), + predecessor_account_id, + target, + tx_bytes_b64, + &mut self.nonce, + ); + + match result { + Ok(promise) => PromiseOrValue::Promise(promise), + Err(Error::Relayer(_)) if env::signer_account_id() == current_account_id => { + let promise = create_ban_relayer_promise(current_account_id); + PromiseOrValue::Promise(promise) + } + Err(e) => PromiseOrValue::Value(e.into()), + } + } + + /// Callback after checking if an address is contained in the registrar. + /// This check happens when the target is another eth implicit account to + /// confirm that the relayer really did check for a named account with that address. + #[private] + pub fn address_check_callback( + &mut self, + target: AccountId, + action: near_action::Action, + ) -> PromiseOrValue { + let maybe_account_id: Option = match env::promise_result(0) { + PromiseResult::Failed => { + return PromiseOrValue::Value(ExecuteResponse { + success: false, + success_value: None, + error: Some("Call to Address Registrar contract failed".into()), + }); + } + PromiseResult::Successful(value) => serde_json::from_slice(&value) + .unwrap_or_else(|_| env::panic_str("Unexpected response from account registrar")), + }; + let current_account_id = env::current_account_id(); + let promise = if maybe_account_id.is_some() { + if env::signer_account_id() == current_account_id { + create_ban_relayer_promise(current_account_id) + } else { + return PromiseOrValue::Value(ExecuteResponse { + success: false, + success_value: None, + error: Some("Invalid target: target is address corresponding to existing named account_id".into()), + }); + } + } else { + let ext = WalletContract::ext(current_account_id).with_unused_gas_weight(1); + match action_to_promise(target, action).map(|p| p.then(ext.rlp_execute_callback())) { + Ok(p) => p, + Err(e) => { + return PromiseOrValue::Value(e.into()); + } + } + }; + PromiseOrValue::Promise(promise) + } + + #[private] + pub fn rlp_execute_callback(&mut self) -> ExecuteResponse { + let n = env::promise_results_count(); + let mut success_value = None; + for i in 0..n { + match env::promise_result(i) { + PromiseResult::Failed => { + return ExecuteResponse { + success: false, + success_value: None, + error: Some("Failed Near promise".into()), + }; + } + PromiseResult::Successful(value) => success_value = Some(value), + } + } + ExecuteResponse { + success: true, + success_value, + error: None, + } + } + + #[private] + pub fn ban_relayer(&mut self) -> ExecuteResponse { + ExecuteResponse { + success: false, + success_value: None, + error: Some("Error: faulty relayer".into()), + } + } +} + +fn inner_rlp_execute( + current_account_id: AccountId, + predecessor_account_id: AccountId, + target: AccountId, + tx_bytes_b64: String, + nonce: &mut u64, +) -> Result { + if *nonce == u64::MAX { + return Err(Error::AccountNonceExhausted); + } + let context = ExecutionContext::new( + current_account_id.clone(), + predecessor_account_id, + env::attached_deposit(), + )?; + + let (action, validation_outcome) = + internal::parse_rlp_tx_to_action(&tx_bytes_b64, &target, &context, nonce)?; + let promise = match validation_outcome { + TransactionValidationOutcome::Validated => { + let ext = WalletContract::ext(current_account_id).with_unused_gas_weight(1); + action_to_promise(target, action)?.then(ext.rlp_execute_callback()) + } + TransactionValidationOutcome::AddressCheckRequired(address) => { + let ext = WalletContract::ext(current_account_id).with_unused_gas_weight(1); + let address_registrar = { + let account_id = ADDRESS_REGISTRAR_ACCOUNT_ID + .trim() + .parse() + .unwrap_or_else(|_| env::panic_str("Invalid address registrar")); + ext_registrar::ext(account_id).with_static_gas(Gas::from_tgas(5)) + }; + let address = format!("0x{}", hex::encode(address)); + address_registrar + .lookup(address) + .then(ext.address_check_callback(target, action)) + } + }; + Ok(promise) +} + +fn action_to_promise(target: AccountId, action: near_action::Action) -> Result { + match action { + near_action::Action::FunctionCall(action) => Ok(Promise::new(target).function_call( + action.method_name, + action.args, + action.deposit, + action.gas, + )), + near_action::Action::Transfer(action) => Ok(Promise::new(target).transfer(action.deposit)), + near_action::Action::Stake(action) => { + Ok(Promise::new(target).stake(action.stake, action.public_key)) + } + near_action::Action::AddKey(action) => match action.access_key.permission { + near_action::AccessKeyPermission::FullAccess => Err(Error::User( + UserError::UnsupportedAction(UnsupportedAction::AddFullAccessKey), + )), + near_action::AccessKeyPermission::FunctionCall(access) => Ok(Promise::new(target) + .add_access_key_allowance_with_nonce( + action.public_key, + access + .allowance + .and_then(Allowance::limited) + .unwrap_or(Allowance::Unlimited), + access.receiver_id, + access.method_names.join(","), + action.access_key.nonce, + )), + }, + near_action::Action::DeleteKey(action) => { + Ok(Promise::new(target).delete_key(action.public_key)) + } + near_action::Action::CreateAccount(_) => Err(Error::User(UserError::UnsupportedAction( + UnsupportedAction::CreateAccount, + ))), + near_action::Action::DeployContract(_) => Err(Error::User(UserError::UnsupportedAction( + UnsupportedAction::DeployContract, + ))), + near_action::Action::DeleteAccount(_) => Err(Error::User(UserError::UnsupportedAction( + UnsupportedAction::DeleteAccount, + ))), + near_action::Action::Delegate(_) => Err(Error::User(UserError::UnsupportedAction( + UnsupportedAction::Delegate, + ))), + } +} + +fn create_ban_relayer_promise(current_account_id: AccountId) -> Promise { + let pk = env::signer_account_pk(); + Promise::new(current_account_id) + .delete_key(pk) + .function_call_weight( + "ban_relayer".into(), + Vec::new(), + NearToken::from_yoctonear(0), + Gas::from_tgas(1), + GasWeight(1), + ) +} + +#[near_sdk::ext_contract(ext_registrar)] +trait AddressRegistrar { + fn lookup(&self, address: String) -> Option; +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/near_action.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/near_action.rs new file mode 100644 index 00000000000..e43cb7bb6c7 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/near_action.rs @@ -0,0 +1,87 @@ +//! Definition of `Action` for Near protocol. +//! Unfortunately we cannot use `near-primitives` directly in the contract +//! because it uses dependencies that do not compile to Wasm (at least +//! not without some extra feature flags that `near-primitives` currently +//! does not include). + +use near_sdk::{AccountId, Gas, NearToken, PublicKey}; + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub enum Action { + CreateAccount(CreateAccountAction), + DeployContract(DeployContractAction), + FunctionCall(FunctionCallAction), + Transfer(TransferAction), + Stake(StakeAction), + AddKey(AddKeyAction), + DeleteKey(DeleteKeyAction), + DeleteAccount(DeleteAccountAction), + Delegate(SignedDelegateAction), +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct CreateAccountAction {} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct DeployContractAction { + pub code: Vec, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct FunctionCallAction { + pub method_name: String, + pub args: Vec, + pub gas: Gas, + pub deposit: NearToken, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct TransferAction { + pub deposit: NearToken, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct StakeAction { + pub stake: NearToken, + pub public_key: PublicKey, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct AddKeyAction { + pub public_key: PublicKey, + pub access_key: AccessKey, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct AccessKey { + pub nonce: u64, + pub permission: AccessKeyPermission, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub enum AccessKeyPermission { + FullAccess, + FunctionCall(FunctionCallPermission), +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct FunctionCallPermission { + pub allowance: Option, + pub receiver_id: AccountId, + pub method_names: Vec, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct DeleteKeyAction { + pub public_key: PublicKey, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct DeleteAccountAction { + pub beneficiary_id: AccountId, +} + +/// This is just a placeholder for now since Delegate actions will +/// not be supported by the Wallet Contract in V1. +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct SignedDelegateAction; diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/caller_error.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/caller_error.rs new file mode 100644 index 00000000000..13b98504c33 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/caller_error.rs @@ -0,0 +1,126 @@ +//! A suite of tests for code paths handling error cases where the `rlp_execute` function +//! is called by an external account (as opposed to the Wallet Contract calling itself). +//! Since `rlp_execute` is public, it must be impossible for an external account to +//! cause harm to the Wallet Contract by calling this function. + +use crate::{ + error::{CallerError, Error}, + internal::MAX_YOCTO_NEAR, + tests::{ + utils::{self, codec, test_context::TestContext}, + RLP_EXECUTE, + }, + types::{Action, ExecuteResponse}, +}; +use aurora_engine_types::types::Wei; +use near_workspaces::types::NearToken; + +// If an external account is submitting a valid Ethereum transaction signed by +// the user then it is expected that this external account should cover the entire +// cost of that transaction (including any attached $NEAR). +#[tokio::test] +async fn test_insufficient_value() -> anyhow::Result<()> { + let TestContext { + worker, + wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + let external_account = worker.dev_create_account().await?; + + // Create a transaction (NEP-141 transfer) that requires 1 yoctoNear attached. + let account_id = "aurora"; + let action = Action::FunctionCall { + receiver_id: account_id.into(), + method_name: "ft_transfer".into(), + args: r#"{"receiver_id": "some.account", "amount": "1"}"#.into(), + gas: 5, + yocto_near: 1, + }; + let signed_transaction = utils::create_signed_transaction( + 0, + &account_id.parse().unwrap(), + Wei::zero(), + action, + &wallet_sk, + ); + + let result = wallet_contract + .external_rlp_execute(&external_account, account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::Caller(CallerError::InsufficientAttachedValue).to_string()) + ); + + // Try again with a transaction that has some attached Wei + let transfer_amount = NearToken::from_near(1).as_yoctonear(); + let action = Action::Transfer { + receiver_id: account_id.into(), + yocto_near: 0, + }; + let signed_transaction = utils::create_signed_transaction( + 1, + &account_id.parse().unwrap(), + Wei::new_u128(transfer_amount / (MAX_YOCTO_NEAR as u128)), + action, + &wallet_sk, + ); + let result = wallet_contract + .external_rlp_execute(&external_account, account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::Caller(CallerError::InsufficientAttachedValue).to_string()) + ); + + // It works if we attach the right amount of Near and does not + // spend any tokens from the Wallet Contract. + let initial_wallet_balance = wallet_contract + .inner + .as_account() + .view_account() + .await? + .balance; + let action = Action::Transfer { + receiver_id: external_account.id().to_string(), + yocto_near: 0, + }; + let signed_transaction = utils::create_signed_transaction( + 2, + external_account.id(), + Wei::new_u128(transfer_amount / (MAX_YOCTO_NEAR as u128)), + action, + &wallet_sk, + ); + let result: ExecuteResponse = external_account + .call(wallet_contract.inner.id(), RLP_EXECUTE) + .args_json(serde_json::json!({ + "target": external_account.id(), + "tx_bytes_b64": codec::encode_b64(&codec::rlp_encode(&signed_transaction)) + })) + .max_gas() + .deposit(NearToken::from_yoctonear(transfer_amount)) + .transact() + .await? + .into_result()? + .json()?; + + assert!(result.success); + + let final_wallet_balance = wallet_contract + .inner + .as_account() + .view_account() + .await? + .balance; + + assert!(final_wallet_balance >= initial_wallet_balance); + + Ok(()) +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs new file mode 100644 index 00000000000..7b70266ce6b --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs @@ -0,0 +1,184 @@ +use crate::{ + internal::{hash_to_address, CHAIN_ID, MAX_YOCTO_NEAR}, + tests::utils::{crypto, nep141, test_context::TestContext}, +}; +use aurora_engine_types::types::{Address, Wei}; +use near_sdk::json_types::U128; +use near_workspaces::types::NearToken; + +// The Wallet Contract should understand that transactions to other Wallet +// Contract instances are base token transactions. +#[tokio::test] +async fn test_base_token_transfer() -> anyhow::Result<()> { + const TRANSFER_AMOUNT: NearToken = NearToken::from_near(2); + + let TestContext { + worker, + wallet_contract, + wallet_sk, + wallet_contract_bytes, + .. + } = TestContext::new().await?; + + let (other_wallet, other_address) = + TestContext::deploy_wallet(&worker, &wallet_contract_bytes).await?; + + let initial_wallet_balance = wallet_contract + .inner + .as_account() + .view_account() + .await? + .balance; + let initial_other_balance = other_wallet + .inner + .as_account() + .view_account() + .await? + .balance; + + let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { + nonce: 0.into(), + gas_price: 0.into(), + gas_limit: 0.into(), + to: Some(Address::new(other_address)), + value: Wei::new_u128(TRANSFER_AMOUNT.as_yoctonear() / u128::from(MAX_YOCTO_NEAR)), + data: b"A message for the recipient".to_vec(), + chain_id: CHAIN_ID, + access_list: Vec::new(), + }; + let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); + + let result = wallet_contract + .rlp_execute(other_wallet.inner.id().as_str(), &signed_transaction) + .await?; + + assert!(result.success); + + let final_wallet_balance = wallet_contract + .inner + .as_account() + .view_account() + .await? + .balance; + let final_other_balance = other_wallet + .inner + .as_account() + .view_account() + .await? + .balance; + + // Receiver balance increases + assert_eq!( + final_other_balance.as_yoctonear(), + initial_other_balance.as_yoctonear() + TRANSFER_AMOUNT.as_yoctonear() + ); + // Sender balance decreases (by a little more than the + // `TRANSFER_AMOUNT` due to gas spent to execute the transaction) + let diff = NearToken::from_yoctonear( + initial_wallet_balance.as_yoctonear() + - (final_wallet_balance.as_yoctonear() + TRANSFER_AMOUNT.as_yoctonear()), + ); + assert!(diff < NearToken::from_millinear(2)); + + Ok(()) +} + +// The Wallet Contract should understand the ERC-20 standard and map +// it to NEP-141 function calls. +#[tokio::test] +async fn test_erc20_emulation() -> anyhow::Result<()> { + const MINT_AMOUNT: NearToken = NearToken::from_near(100); + const TRANSFER_AMOUNT: NearToken = NearToken::from_near(32); + + let TestContext { + worker, + wallet_contract, + wallet_sk, + wallet_address, + wallet_contract_bytes, + .. + } = TestContext::new().await?; + + let token_contract = nep141::Nep141::deploy(&worker).await?; + token_contract + .mint(wallet_contract.inner.id(), MINT_AMOUNT.as_yoctonear()) + .await?; + + // Check balance + let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { + nonce: 0.into(), + gas_price: 0.into(), + gas_limit: 0.into(), + to: Some(Address::new(hash_to_address( + &token_contract.contract.id().as_str().parse().unwrap(), + ))), + value: Wei::zero(), + data: [ + crate::eth_emulation::ERC20_BALANCE_OF_SELECTOR.to_vec(), + ethabi::encode(&[ethabi::Token::Address(wallet_address)]), + ] + .concat(), + chain_id: CHAIN_ID, + access_list: Vec::new(), + }; + let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); + + let result = wallet_contract + .rlp_execute(token_contract.contract.id().as_str(), &signed_transaction) + .await?; + + let balance: U128 = serde_json::from_slice(result.success_value.as_ref().unwrap())?; + assert_eq!( + balance.0, + token_contract + .ft_balance_of(wallet_contract.inner.id()) + .await? + ); + + // Do a transfer to another account + let (other_wallet, other_address) = + TestContext::deploy_wallet(&worker, &wallet_contract_bytes).await?; + token_contract + .mint(other_wallet.inner.id(), MINT_AMOUNT.as_yoctonear()) + .await?; + let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { + nonce: 1.into(), + gas_price: 0.into(), + gas_limit: 0.into(), + to: Some(Address::new(hash_to_address( + &token_contract.contract.id().as_str().parse().unwrap(), + ))), + value: Wei::zero(), + data: [ + crate::eth_emulation::ERC20_TRANSFER_SELECTOR.to_vec(), + ethabi::encode(&[ + ethabi::Token::Address(other_address), + ethabi::Token::Uint(TRANSFER_AMOUNT.as_yoctonear().into()), + ]), + ] + .concat(), + chain_id: CHAIN_ID, + access_list: Vec::new(), + }; + let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); + + let result = wallet_contract + .rlp_execute(token_contract.contract.id().as_str(), &signed_transaction) + .await?; + + assert!(result.success); + assert_eq!( + MINT_AMOUNT.as_yoctonear() - TRANSFER_AMOUNT.as_yoctonear(), + token_contract + .ft_balance_of(wallet_contract.inner.id()) + .await? + ); + assert_eq!( + MINT_AMOUNT.as_yoctonear() + TRANSFER_AMOUNT.as_yoctonear(), + token_contract + .ft_balance_of(other_wallet.inner.id()) + .await? + ); + + Ok(()) +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/mod.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/mod.rs new file mode 100644 index 00000000000..e8d1c5cf0be --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/mod.rs @@ -0,0 +1,9 @@ +mod caller_error; +mod emulation; +mod relayer; +mod sanity; +mod user_error; +mod utils; + +pub const RLP_EXECUTE: &str = "rlp_execute"; +pub const GET_NONCE: &str = "get_nonce"; diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs new file mode 100644 index 00000000000..6256769fb55 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs @@ -0,0 +1,337 @@ +use crate::{ + internal::{hash_to_address, CHAIN_ID}, + tests::{ + utils::{ + self, codec, crypto, nep141, + test_context::{TestContext, WalletContract}, + }, + RLP_EXECUTE, + }, + types::{Action, ExecuteResponse}, +}; +use aurora_engine_types::types::{Address, Wei}; +use near_workspaces::{ + network::Sandbox, + types::{AccessKeyPermission, SecretKey}, + Contract, Worker, +}; + +// A relayer can use its own Near account to send a transaction containing data +// signed by the user which adds a FunctionCall access key to the Wallet +// Contract account. This allows the relayer to send transactions on the user's +// behalf while the user covers the gas costs. +#[tokio::test] +async fn test_register_relayer() -> anyhow::Result<()> { + let TestContext { + worker, + mut wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + let relayer_pk = wallet_contract.register_relayer(&worker).await?; + let key = wallet_contract + .inner + .as_account() + .view_access_key(&relayer_pk) + .await?; + match &key.permission { + AccessKeyPermission::FunctionCall(access) => { + assert_eq!(access.allowance, None); + assert_eq!( + access.receiver_id.as_str(), + wallet_contract.inner.id().as_str() + ); + assert_eq!(&access.method_names, &[RLP_EXECUTE]); + } + _ => panic!("Unexpected full access key"), + } + + // Should be able to submit transactions using the new key + utils::deploy_and_call_hello(&worker, &wallet_contract, &wallet_sk, 1).await?; + + // If the relayer is dishonest then its key is revoked. + // In this case the relayer will try to repeat a nonce value. + let result = utils::deploy_and_call_hello(&worker, &wallet_contract, &wallet_sk, 1).await; + let error_message = format!("{:?}", result.unwrap_err()); + assert!(error_message.contains("faulty relayer")); + + assert_revoked_key(&wallet_contract.inner, &relayer_pk).await; + + Ok(()) +} + +// If the relayer sends garbage data to the Wallet Contract then it is banned. +#[tokio::test] +async fn test_relayer_invalid_tx_data() -> anyhow::Result<()> { + let TestContext { + worker, + mut wallet_contract, + .. + } = TestContext::new().await?; + + async fn new_relayer( + worker: &Worker, + wc: &mut WalletContract, + ) -> anyhow::Result { + wc.register_relayer(worker).await?; + let sk = wc.inner.as_account().secret_key().clone(); + Ok(sk) + } + + async fn rlp_execute( + relayer_key: &SecretKey, + wc: &WalletContract, + tx_bytes: &[u8], + ) -> anyhow::Result<()> { + let relayer_pk = relayer_key.public_key(); + + let result: ExecuteResponse = wc + .inner + .call(RLP_EXECUTE) + .args_json(serde_json::json!({ + "target": "some.account.near", + "tx_bytes_b64": codec::encode_b64(tx_bytes) + })) + .max_gas() + .transact() + .await? + .into_result()? + .json()?; + + assert!(!result.success); + assert_eq!(result.error.as_deref(), Some("Error: faulty relayer")); + + assert_revoked_key(&wc.inner, &relayer_pk).await; + + Ok(()) + } + + let inputs: [&[u8]; 2] = [b"random_garbage_data", &[]]; + let relayer_keys = { + // Need to generate all the relayer keys first because they are + // going to get banned as we run the different inputs in the later loop. + let mut tmp = Vec::new(); + for _ in 0..(inputs.len()) { + tmp.push(new_relayer(&worker, &mut wallet_contract).await?); + } + tmp + }; + + for (input, sk) in inputs.into_iter().zip(relayer_keys) { + wallet_contract + .inner + .as_account_mut() + .set_secret_key(sk.clone()); + rlp_execute(&sk, &wallet_contract, input).await?; + } + + Ok(()) +} + +// Tests case where relayer sends a transaction signed by the wrong account. +#[tokio::test] +async fn test_relayer_invalid_sender() -> anyhow::Result<()> { + let TestContext { + worker, + mut wallet_contract, + wallet_contract_bytes, + .. + } = TestContext::new().await?; + + let wrong_wallet_sk = TestContext::deploy_wallet(&worker, &wallet_contract_bytes) + .await? + .0 + .sk; + let relayer_pk = wallet_contract.register_relayer(&worker).await?; + + let target = "aurora"; + let action = Action::Transfer { + receiver_id: target.into(), + yocto_near: 0, + }; + // Transaction signed by wrong secret key + let signed_transaction = utils::create_signed_transaction( + 0, + &target.parse().unwrap(), + Wei::zero(), + action, + &wrong_wallet_sk, + ); + + let result = wallet_contract + .rlp_execute(target, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!(result.error.as_deref(), Some("Error: faulty relayer")); + + assert_revoked_key(&wallet_contract.inner, &relayer_pk).await; + + Ok(()) +} + +// Tests the case where the relayer sets the `target` to a named account which does not +// hash to the `to` field of the user's signed Ethereum transaction. +#[tokio::test] +async fn test_relayer_invalid_target() -> anyhow::Result<()> { + let TestContext { + worker, + mut wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + let relayer_pk = wallet_contract.register_relayer(&worker).await?; + + let real_target = "aurora"; + let action = Action::Transfer { + receiver_id: real_target.into(), + yocto_near: 0, + }; + let signed_transaction = utils::create_signed_transaction( + 0, + &real_target.parse().unwrap(), + Wei::zero(), + action, + &wallet_sk, + ); + + let result = wallet_contract + .rlp_execute(&format!("other.{real_target}"), &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!(result.error.as_deref(), Some("Error: faulty relayer")); + + assert_revoked_key(&wallet_contract.inner, &relayer_pk).await; + + Ok(()) +} + +// Tests the situation where the relayer sets `target == tx.to` when it should have +// looked up the named account corresponding to `tx.to`. In this case the relayer +// should be banned for being lazy. +#[tokio::test] +async fn test_relayer_invalid_address_target() -> anyhow::Result<()> { + let TestContext { + worker, + mut wallet_contract, + wallet_sk, + wallet_address, + address_registrar, + .. + } = TestContext::new().await?; + + // Deploy a NEP-141 contract and register its address. + // Registering should prevent a lazy relayer from setting the target incorrectly. + let token_contract = nep141::Nep141::deploy(&worker).await?; + let register_output: Option = address_registrar + .call("register") + .args_json(serde_json::json!({ + "account_id": token_contract.contract.id().as_str() + })) + .max_gas() + .transact() + .await? + .json()?; + let token_address: [u8; 20] = hex::decode( + register_output + .as_ref() + .unwrap() + .strip_prefix("0x") + .unwrap(), + )? + .try_into() + .unwrap(); + assert_eq!( + token_address, + hash_to_address(&token_contract.contract.id().as_str().parse().unwrap(),).0 + ); + + // Set up a relayer with control to send transactions via the Wallet Contract account. + let relayer_pk = wallet_contract.register_relayer(&worker).await?; + + // The user submits a transaction to interact with the NEP-141 contract. + let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { + nonce: 0.into(), + gas_price: 0.into(), + gas_limit: 0.into(), + to: Some(Address::from_array(token_address)), + value: Wei::zero(), + data: [ + crate::eth_emulation::ERC20_BALANCE_OF_SELECTOR.to_vec(), + ethabi::encode(&[ethabi::Token::Address(wallet_address)]), + ] + .concat(), + chain_id: CHAIN_ID, + access_list: Vec::new(), + }; + let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); + + // Relayer fails to set `target` correctly + let result = wallet_contract + .rlp_execute(register_output.unwrap().as_str(), &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!(result.error.as_deref(), Some("Error: faulty relayer")); + + assert_revoked_key(&wallet_contract.inner, &relayer_pk).await; + + Ok(()) +} + +// A relayer sending a transaction signed with the wrong chain id is a ban-worthy offense. +#[tokio::test] +async fn test_relayer_wrong_chain_id() -> anyhow::Result<()> { + let TestContext { + worker, + mut wallet_contract, + wallet_sk, + wallet_address, + .. + } = TestContext::new().await?; + + let relayer_pk = wallet_contract.register_relayer(&worker).await?; + + let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { + nonce: 0.into(), + gas_price: 0.into(), + gas_limit: 0.into(), + to: Some(Address::new(wallet_address)), + value: Wei::zero(), + data: [ + crate::eth_emulation::ERC20_BALANCE_OF_SELECTOR.to_vec(), + ethabi::encode(&[ethabi::Token::Address(wallet_address)]), + ] + .concat(), + chain_id: CHAIN_ID + 1, + access_list: Vec::new(), + }; + let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); + + let result = wallet_contract + .rlp_execute(wallet_contract.inner.id().as_str(), &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!(result.error.as_deref(), Some("Error: faulty relayer")); + + assert_revoked_key(&wallet_contract.inner, &relayer_pk).await; + + Ok(()) +} + +async fn assert_revoked_key( + wallet_contract: &Contract, + relayer_pk: &near_workspaces::types::PublicKey, +) { + let key_query = wallet_contract + .as_account() + .view_access_key(relayer_pk) + .await; + + let error_message = format!("{:?}", key_query.unwrap_err()); + assert!(error_message.contains("UnknownAccessKey")); +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/res/hello.wasm b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/res/hello.wasm new file mode 100755 index 0000000000000000000000000000000000000000..4cba2085bf2f4d353a9571ce2102c56316688afd GIT binary patch literal 215153 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

?}W*?m~&F(|kDGro#! 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 literal 0 HcmV?d00001 diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/res/nep141.wasm b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/res/nep141.wasm new file mode 100755 index 0000000000000000000000000000000000000000..b501278c16159e91184360dd4967c5de85aee73e GIT binary patch literal 180658 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 C=UwRl literal 0 HcmV?d00001 diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/sanity.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/sanity.rs new file mode 100644 index 00000000000..c77f118a45c --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/sanity.rs @@ -0,0 +1,100 @@ +use aurora_engine_types::types::Wei; +use near_sdk::NearToken; + +use crate::{ + internal::MAX_YOCTO_NEAR, + tests::utils::{self, test_context::TestContext}, + types::Action, +}; + +// The initial nonce value for a Wallet Contract should be 0. +#[tokio::test] +async fn test_initial_nonce() -> anyhow::Result<()> { + let TestContext { + wallet_contract, .. + } = TestContext::new().await?; + + let nonce = wallet_contract.get_nonce().await?; + assert_eq!(nonce, 0); + + Ok(()) +} + +// The Wallet Contract should be able to call other Near smart contracts +#[tokio::test] +async fn test_function_call_action_success() -> anyhow::Result<()> { + let TestContext { + worker, + wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + utils::deploy_and_call_hello(&worker, &wallet_contract, &wallet_sk, 0).await?; + + // After the transaction the nonce is incremented + let nonce = wallet_contract.get_nonce().await?; + assert_eq!(nonce, 1); + + Ok(()) +} + +// The Wallet Contract should be able to send $NEAR to other Near accounts. +#[tokio::test] +async fn test_base_token_transfer_success() -> anyhow::Result<()> { + let TestContext { + worker, + wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + let transfer_amount = NearToken::from_near(2).as_yoctonear() + 1; + let receiver_account = worker.root_account().unwrap(); + + let initial_wallet_balance = wallet_contract + .inner + .as_account() + .view_account() + .await + .unwrap() + .balance; + let initial_receiver_balance = receiver_account.view_account().await.unwrap().balance; + + let receiver_id = receiver_account.id().as_str().into(); + let action = Action::Transfer { + receiver_id, + yocto_near: 1, + }; + let value = Wei::new_u128(transfer_amount / (MAX_YOCTO_NEAR as u128)); + let signed_transaction = + utils::create_signed_transaction(0, receiver_account.id(), value, action, &wallet_sk); + + let result = wallet_contract + .rlp_execute(receiver_account.id().as_str(), &signed_transaction) + .await?; + assert!(result.success); + + let final_wallet_balance = wallet_contract + .inner + .as_account() + .view_account() + .await + .unwrap() + .balance; + let final_receiver_balance = receiver_account.view_account().await.unwrap().balance; + + // Check token balances + assert_eq!( + final_receiver_balance.as_yoctonear() - initial_receiver_balance.as_yoctonear(), + transfer_amount + ); + // Wallet loses a little more $NEAR than the transfer amount + // due to gas spent on the transaction. + let diff = initial_wallet_balance.as_yoctonear() + - final_wallet_balance.as_yoctonear() + - transfer_amount; + assert!(diff < NearToken::from_millinear(2).as_yoctonear()); + + Ok(()) +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs new file mode 100644 index 00000000000..d7e3563e8b4 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs @@ -0,0 +1,446 @@ +//! A suite of tests for code paths handling cases where the user signed transaction +//! data that is invalid in some way. This is as opposed to errors which arise +//! from faulty relayers. + +use crate::{ + error::{Error, UnsupportedAction, UserError}, + internal::{hash_to_address, CHAIN_ID}, + tests::utils::{self, crypto, test_context::TestContext}, + types::{Action, FUNCTION_CALL_SELECTOR}, +}; +use aurora_engine_types::types::{Address, Wei}; +use near_workspaces::types::{KeyType, SecretKey}; + +// Transactions which would deploy an EVM contract are not allowed because +// there is no native EVM bytecode interpreter on Near. +#[tokio::test] +async fn test_evm_deploy() -> anyhow::Result<()> { + let TestContext { + wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { + nonce: 0.into(), + gas_price: 0.into(), + gas_limit: 0.into(), + to: None, + value: Wei::zero(), + data: Vec::new(), + chain_id: CHAIN_ID, + access_list: Vec::new(), + }; + let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); + + let result = wallet_contract + .rlp_execute("aurora", &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::User(UserError::EvmDeployDisallowed).to_string()) + ); + + Ok(()) +} + +// The Near value of a transaction is equal to `tx.value * 1e6 + action.yocto_near`. +// Near values must be 128-bit numbers. Therefore `tx.value` cannot be larger than +// `u128::MAX // 1e6`. +#[tokio::test] +async fn test_value_too_large() -> anyhow::Result<()> { + let TestContext { + wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + let account_id = "aurora"; + let action = Action::Transfer { + receiver_id: account_id.into(), + yocto_near: 0, + }; + let signed_transaction = utils::create_signed_transaction( + 0, + &account_id.parse().unwrap(), + Wei::new_u128(u128::MAX), + action, + &wallet_sk, + ); + + let result = wallet_contract + .rlp_execute(account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::User(UserError::ValueTooLarge).to_string()) + ); + + Ok(()) +} + +// Test case where `AddKey`/`DeleteKey` action contains an unknown public key kind +#[tokio::test] +async fn test_unknown_public_key_kind() -> anyhow::Result<()> { + let TestContext { + wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + let account_id = "aurora"; + let action = Action::DeleteKey { + public_key_kind: 2, + public_key: b"a_new_key_type".to_vec(), + }; + let signed_transaction = utils::create_signed_transaction( + 0, + &account_id.parse().unwrap(), + Wei::zero(), + action, + &wallet_sk, + ); + + let result = wallet_contract + .rlp_execute(account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::User(UserError::UnknownPublicKeyKind).to_string()) + ); + + let action = Action::AddKey { + public_key_kind: 2, + public_key: b"some_key".to_vec(), + nonce: 0, + is_full_access: false, + is_limited_allowance: false, + allowance: 0, + receiver_id: account_id.into(), + method_names: Vec::new(), + }; + let signed_transaction = utils::create_signed_transaction( + 1, + &account_id.parse().unwrap(), + Wei::zero(), + action, + &wallet_sk, + ); + + let result = wallet_contract + .rlp_execute(account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::User(UserError::UnknownPublicKeyKind).to_string()) + ); + + Ok(()) +} + +// Test case where `AddKey`/`DeleteKey` action contains invalid public key bytes +#[tokio::test] +async fn test_invalid_public_key() -> anyhow::Result<()> { + async fn assert_invalid_pk( + ctx: &TestContext, + public_key_kind: u8, + public_key: Vec, + expected_error: UserError, + ) -> anyhow::Result<()> { + let wallet_contract = &ctx.wallet_contract; + let wallet_sk = &ctx.wallet_sk; + + let nonce = wallet_contract.get_nonce().await?; + let account_id = "aurora"; + let action = Action::DeleteKey { + public_key_kind, + public_key: public_key.clone(), + }; + let signed_transaction = utils::create_signed_transaction( + nonce, + &account_id.parse().unwrap(), + Wei::zero(), + action, + wallet_sk, + ); + + let result = wallet_contract + .rlp_execute(account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::User(expected_error.clone()).to_string()) + ); + + let action = Action::AddKey { + public_key_kind, + public_key, + nonce: 0, + is_full_access: false, + is_limited_allowance: false, + allowance: 0, + receiver_id: account_id.into(), + method_names: Vec::new(), + }; + let signed_transaction = utils::create_signed_transaction( + nonce + 1, + &account_id.parse().unwrap(), + Wei::zero(), + action, + wallet_sk, + ); + + let result = wallet_contract + .rlp_execute(account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!(result.error, Some(Error::User(expected_error).to_string())); + + Ok(()) + } + + let ctx = TestContext::new().await?; + + assert_invalid_pk(&ctx, 0, Vec::new(), UserError::InvalidEd25519Key).await?; + assert_invalid_pk( + &ctx, + 0, + b"wrong_length".to_vec(), + UserError::InvalidEd25519Key, + ) + .await?; + + assert_invalid_pk(&ctx, 1, Vec::new(), UserError::InvalidSecp256k1Key).await?; + assert_invalid_pk( + &ctx, + 1, + b"wrong_length".to_vec(), + UserError::InvalidSecp256k1Key, + ) + .await?; + + Ok(()) +} + +// Tests case where we try to add an access key with an invalid `receiver_id` +#[tokio::test] +async fn test_invalid_public_key_account_id() -> anyhow::Result<()> { + let TestContext { + wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + let key = SecretKey::from_random(KeyType::ED25519); + let account_id = "aurora"; + let non_account_id = "---***---"; + let action = Action::AddKey { + public_key_kind: 0, + public_key: key.public_key().key_data().to_vec(), + nonce: 0, + is_full_access: false, + is_limited_allowance: false, + allowance: 0, + receiver_id: non_account_id.into(), + method_names: Vec::new(), + }; + let signed_transaction = utils::create_signed_transaction( + 0, + &account_id.parse().unwrap(), + Wei::zero(), + action, + &wallet_sk, + ); + + let result = wallet_contract + .rlp_execute(account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::User(UserError::InvalidAccessKeyAccountId).to_string()) + ); + + Ok(()) +} + +// User's are not allowed to add full access keys to the account. +// This would be too dangerous as it could allow for undefined behaviour +// such as deploying a different contract to an Eth implicit address. +#[tokio::test] +async fn test_cannot_add_full_access_key() -> anyhow::Result<()> { + let TestContext { + wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + let key = SecretKey::from_random(KeyType::ED25519); + let action = Action::AddKey { + public_key_kind: 0, + public_key: key.public_key().key_data().to_vec(), + nonce: 0, + is_full_access: true, + is_limited_allowance: false, + allowance: 0, + receiver_id: String::new(), + method_names: Vec::new(), + }; + let signed_transaction = utils::create_signed_transaction( + 0, + wallet_contract.inner.id(), + Wei::zero(), + action, + &wallet_sk, + ); + + let result = wallet_contract + .rlp_execute(wallet_contract.inner.id().as_str(), &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some( + Error::User(UserError::UnsupportedAction( + UnsupportedAction::AddFullAccessKey + )) + .to_string() + ) + ); + + Ok(()) +} + +// Cases where `tx.data` cannot be parsed into a known +// Action or emulated Ethereum standard. +#[tokio::test] +async fn test_bad_data() -> anyhow::Result<()> { + let TestContext { + wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + let account_id = "aurora"; + let to = Address::new(hash_to_address(&account_id.parse().unwrap())); + let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { + nonce: 0.into(), + gas_price: 0.into(), + gas_limit: 0.into(), + to: Some(to), + value: Wei::zero(), + data: hex::decode("deadbeef").unwrap(), + chain_id: CHAIN_ID, + access_list: Vec::new(), + }; + let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); + + let result = wallet_contract + .rlp_execute(account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::User(UserError::UnknownFunctionSelector).to_string()) + ); + + let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { + nonce: 1.into(), + gas_price: 0.into(), + gas_limit: 0.into(), + to: Some(to), + value: Wei::zero(), + data: [ + FUNCTION_CALL_SELECTOR.to_vec(), + hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(), + ] + .concat(), + chain_id: CHAIN_ID, + access_list: Vec::new(), + }; + let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); + + let result = wallet_contract + .rlp_execute(account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::User(UserError::InvalidAbiEncodedData).to_string()) + ); + + let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { + nonce: 2.into(), + gas_price: 0.into(), + gas_limit: 0.into(), + to: Some(to), + value: Wei::zero(), + data: Vec::new(), + chain_id: CHAIN_ID, + access_list: Vec::new(), + }; + let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); + + let result = wallet_contract + .rlp_execute(account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::User(UserError::InvalidAbiEncodedData).to_string()) + ); + + Ok(()) +} + +// Test case where the action contains more than 1_000_000 yocotoNear directly. +#[tokio::test] +async fn test_excess_yocto() -> anyhow::Result<()> { + let TestContext { + wallet_contract, + wallet_sk, + .. + } = TestContext::new().await?; + + let account_id = "aurora"; + let action = Action::Transfer { + receiver_id: account_id.into(), + yocto_near: crate::internal::MAX_YOCTO_NEAR + 1, + }; + let signed_transaction = utils::create_signed_transaction( + 0, + &account_id.parse().unwrap(), + Wei::new_u64(1), + action, + &wallet_sk, + ); + + let result = wallet_contract + .rlp_execute(account_id, &signed_transaction) + .await?; + + assert!(!result.success); + assert_eq!( + result.error, + Some(Error::User(UserError::ExcessYoctoNear).to_string()) + ); + + Ok(()) +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/codec.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/codec.rs new file mode 100644 index 00000000000..95b5e1d8519 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/codec.rs @@ -0,0 +1,86 @@ +use crate::types::Action; +use aurora_engine_transactions::EthTransactionKind; + +pub fn abi_encode(action: Action) -> Vec { + let mut buf = Vec::new(); + match action { + Action::FunctionCall { + receiver_id, + method_name, + args, + gas, + yocto_near, + } => { + buf.extend_from_slice(crate::types::FUNCTION_CALL_SELECTOR); + let tokens = &[ + ethabi::Token::String(receiver_id), + ethabi::Token::String(method_name), + ethabi::Token::Bytes(args), + ethabi::Token::Uint(gas.into()), + ethabi::Token::Uint(yocto_near.into()), + ]; + buf.extend_from_slice(ðabi::encode(tokens)); + } + Action::Transfer { + receiver_id, + yocto_near, + } => { + buf.extend_from_slice(crate::types::TRANSFER_SELECTOR); + let tokens = &[ + ethabi::Token::String(receiver_id), + ethabi::Token::Uint(yocto_near.into()), + ]; + buf.extend_from_slice(ðabi::encode(tokens)); + } + Action::AddKey { + public_key_kind, + public_key, + nonce, + is_full_access, + is_limited_allowance, + allowance, + receiver_id, + method_names, + } => { + buf.extend_from_slice(crate::types::ADD_KEY_SELECTOR); + let tokens = &[ + ethabi::Token::Uint(public_key_kind.into()), + ethabi::Token::Bytes(public_key), + ethabi::Token::Uint(nonce.into()), + ethabi::Token::Bool(is_full_access), + ethabi::Token::Bool(is_limited_allowance), + ethabi::Token::Uint(allowance.into()), + ethabi::Token::String(receiver_id), + ethabi::Token::Array( + method_names + .into_iter() + .map(ethabi::Token::String) + .collect(), + ), + ]; + buf.extend_from_slice(ðabi::encode(tokens)); + } + Action::DeleteKey { + public_key_kind, + public_key, + } => { + buf.extend_from_slice(crate::types::DELETE_KEY_SELECTOR); + let tokens = &[ + ethabi::Token::Uint(public_key_kind.into()), + ethabi::Token::Bytes(public_key), + ]; + buf.extend_from_slice(ðabi::encode(tokens)); + } + }; + buf +} + +pub fn rlp_encode(transaction: &EthTransactionKind) -> Vec { + transaction.into() +} + +pub fn encode_b64(input: &[u8]) -> String { + use base64::Engine; + let engine = base64::engine::general_purpose::STANDARD; + engine.encode(input) +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/crypto.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/crypto.rs new file mode 100644 index 00000000000..602c5902b29 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/crypto.rs @@ -0,0 +1,25 @@ +use aurora_engine_transactions::{eip_2930::Transaction2930, EthTransactionKind}; +use aurora_engine_types::U256; +use near_crypto::{SecretKey, Signature}; + +pub fn sign_transaction(transaction: Transaction2930, sk: &SecretKey) -> EthTransactionKind { + let mut rlp_stream = rlp::RlpStream::new(); + rlp_stream.append(&aurora_engine_transactions::eip_2930::TYPE_BYTE); + transaction.rlp_append_unsigned(&mut rlp_stream); + let message_hash = crate::internal::keccak256(rlp_stream.as_raw()); + let signature = sk.sign(&message_hash); + let bytes: [u8; 65] = match signature { + Signature::SECP256K1(x) => x.into(), + _ => panic!(), + }; + let v = bytes[64]; + let r = U256::from_big_endian(&bytes[0..32]); + let s = U256::from_big_endian(&bytes[32..64]); + let signed_transaction = aurora_engine_transactions::eip_2930::SignedTransaction2930 { + transaction, + parity: v, + r, + s, + }; + EthTransactionKind::Eip2930(signed_transaction) +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs new file mode 100644 index 00000000000..7432501403a --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs @@ -0,0 +1,66 @@ +use crate::{ + internal::{hash_to_address, CHAIN_ID}, + tests::utils::test_context::WalletContract, + types::Action, +}; +use aurora_engine_transactions::EthTransactionKind; +use aurora_engine_types::types::{Address, Wei}; +use near_crypto::SecretKey; +use near_workspaces::{network::Sandbox, AccountId, Worker}; + +pub mod codec; +pub mod crypto; +pub mod nep141; +pub mod test_context; + +pub async fn deploy_and_call_hello( + worker: &Worker, + wallet_contract: &WalletContract, + wallet_sk: &SecretKey, + nonce: u64, +) -> anyhow::Result<()> { + let hello_bytes = tokio::fs::read("src/tests/res/hello.wasm").await?; + let hello_contract = worker.dev_deploy(&hello_bytes).await?; + + let action = Action::FunctionCall { + receiver_id: hello_contract.id().to_string(), + method_name: "greet".into(), + args: br#"{"name": "Aurora"}"#.to_vec(), + gas: 5_000_000_000_000, + yocto_near: 0, + }; + let signed_transaction = + create_signed_transaction(nonce, hello_contract.id(), Wei::zero(), action, wallet_sk); + + let result = wallet_contract + .rlp_execute(hello_contract.id().as_str(), &signed_transaction) + .await?; + + if result.success_value.as_deref() != Some(br#""Hello, Aurora!""#.as_slice()) { + anyhow::bail!("Call to hello contract failed: {:?}", result.error); + } + + Ok(()) +} + +pub fn create_signed_transaction( + nonce: u64, + target: &AccountId, + value: Wei, + action: Action, + wallet_sk: &SecretKey, +) -> EthTransactionKind { + let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { + nonce: nonce.into(), + gas_price: 0.into(), + gas_limit: 0.into(), + to: Some(Address::new(hash_to_address( + &target.as_str().parse().unwrap(), + ))), + value, + data: codec::abi_encode(action), + chain_id: CHAIN_ID, + access_list: Vec::new(), + }; + crypto::sign_transaction(transaction, wallet_sk) +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/nep141.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/nep141.rs new file mode 100644 index 00000000000..1e100afe385 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/nep141.rs @@ -0,0 +1,67 @@ +use near_sdk::json_types::U128; +use near_workspaces::{network::Sandbox, types::NearToken, AccountId, Contract, Worker}; + +const STORAGE_DEPOSIT_AMOUNT: u128 = 1_250_000_000_000_000_000_000; + +pub struct Nep141 { + pub contract: Contract, +} + +impl Nep141 { + pub async fn deploy(worker: &Worker) -> anyhow::Result { + let bytes = tokio::fs::read("src/tests/res/nep141.wasm").await?; + let contract = worker.dev_deploy(&bytes).await?; + + contract + .call("new") + .args_json(serde_json::json!({ + "name": "TestToken", + "symbol": "TTT", + "decimals": 24, + })) + .max_gas() + .transact() + .await? + .into_result()?; + + Ok(Self { contract }) + } + + pub async fn mint(&self, account_id: &AccountId, amount: u128) -> anyhow::Result<()> { + self.contract + .call("storage_deposit") + .args_json(serde_json::json!({ + "account_id": account_id.as_str(), + })) + .deposit(NearToken::from_yoctonear(STORAGE_DEPOSIT_AMOUNT)) + .max_gas() + .transact() + .await? + .into_result()?; + + self.contract + .call("mint") + .args_json(serde_json::json!({ + "account_id": account_id.as_str(), + "amount": U128(amount), + })) + .max_gas() + .transact() + .await? + .into_result()?; + + Ok(()) + } + + pub async fn ft_balance_of(&self, account_id: &AccountId) -> anyhow::Result { + let result: U128 = self + .contract + .view("ft_balance_of") + .args_json(serde_json::json!({ + "account_id": account_id.as_str(), + })) + .await? + .json()?; + Ok(result.0) + } +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs new file mode 100644 index 00000000000..091799d110e --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs @@ -0,0 +1,267 @@ +use crate::{ + tests::{ + utils::{self, codec}, + GET_NONCE, RLP_EXECUTE, + }, + types::{Action, ExecuteResponse}, +}; +use aurora_engine_transactions::EthTransactionKind; +use aurora_engine_types::types::Wei; +use ethabi::Address; +use near_sdk::json_types::U64; +use near_workspaces::{ + network::Sandbox, + types::{KeyType, NearToken, PublicKey, SecretKey}, + Account, Contract, Worker, +}; +use std::{ + ffi::OsStr, + path::{Path, PathBuf}, +}; +use tokio::{process::Command, sync::Mutex}; + +const BASE_DIR: &str = std::env!("CARGO_MANIFEST_DIR"); +const PACKAGE_NAME: &str = std::env!("CARGO_PKG_NAME"); +const INITIAL_BALANCE: NearToken = NearToken::from_near(20); + +// Prevents multiple tests from trying to compile the contracts at the same time. +static LOCK: Mutex<()> = Mutex::const_new(()); + +pub struct WalletContract { + pub inner: Contract, + pub sk: near_crypto::SecretKey, +} + +impl WalletContract { + pub async fn rlp_execute( + &self, + target: &str, + tx: &EthTransactionKind, + ) -> anyhow::Result { + let result: ExecuteResponse = self + .inner + .call(RLP_EXECUTE) + .args_json(serde_json::json!({ + "target": target, + "tx_bytes_b64": codec::encode_b64(&codec::rlp_encode(tx)) + })) + .max_gas() + .transact() + .await? + .into_result()? + .json()?; + + Ok(result) + } + + pub async fn external_rlp_execute( + &self, + caller: &Account, + target: &str, + tx: &EthTransactionKind, + ) -> anyhow::Result { + let result: ExecuteResponse = caller + .call(self.inner.id(), RLP_EXECUTE) + .args_json(serde_json::json!({ + "target": target, + "tx_bytes_b64": codec::encode_b64(&codec::rlp_encode(tx)) + })) + .max_gas() + .transact() + .await? + .into_result()? + .json()?; + + Ok(result) + } + + pub async fn get_nonce(&self) -> anyhow::Result { + let nonce: U64 = self.inner.view(GET_NONCE).await?.json()?; + Ok(nonce.0) + } + + /// Add a new `FunctionCall` access key to the Wallet Contract. + /// The idea is that this allows the relayer to submit transactions signed by + /// the Wallet Contract directly. + pub async fn register_relayer( + &mut self, + worker: &Worker, + ) -> anyhow::Result { + let relayer_account = worker.dev_create_account().await?; + let relayer_key = SecretKey::from_random(KeyType::ED25519); + let relayer_pk = relayer_key.public_key(); + + let action = Action::AddKey { + public_key_kind: 0, + public_key: relayer_pk.key_data().to_vec(), + nonce: 0, + is_full_access: false, + is_limited_allowance: false, + allowance: 0, + receiver_id: self.inner.id().to_string(), + method_names: vec![RLP_EXECUTE.into()], + }; + let nonce = self.get_nonce().await?; + let signed_transaction = + utils::create_signed_transaction(nonce, self.inner.id(), Wei::zero(), action, &self.sk); + + // Call the Wallet Contract from the relayer account to add the key + let result: ExecuteResponse = relayer_account + .call(self.inner.id(), RLP_EXECUTE) + .args_json(serde_json::json!({ + "target": self.inner.id(), + "tx_bytes_b64": codec::encode_b64(&codec::rlp_encode(&signed_transaction)) + })) + .max_gas() + .transact() + .await? + .into_result()? + .json()?; + + assert!( + result.success, + "Adding Relayer's key failed: {:?}", + result.error + ); + + // Tell near-workspaces to use this new key instead when + // signing transactions from the Wallet Contract + self.inner.as_account_mut().set_secret_key(relayer_key); + + Ok(relayer_pk) + } +} + +pub struct TestContext { + pub worker: Worker, + pub wallet_contract: WalletContract, + pub wallet_sk: near_crypto::SecretKey, + pub wallet_address: Address, + pub address_registrar: Contract, + pub wallet_contract_bytes: Vec, +} + +impl TestContext { + pub async fn new() -> anyhow::Result { + let _guard = LOCK.lock().await; + let worker = near_workspaces::sandbox().await?; + + let address_registrar = Self::deploy_address_registrar(&worker).await?; + let wallet_contract_bytes = build_contract(BASE_DIR, PACKAGE_NAME).await?; + // Restore address registrar account id file + let output = Command::new("git") + .current_dir(BASE_DIR) + .args([ + OsStr::new("checkout"), + address_registrar_account_id_path(".").as_os_str(), + ]) + .output() + .await?; + if !output.status.success() { + anyhow::bail!( + "git checkout failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + + let (wallet_contract, wallet_address) = + Self::deploy_wallet(&worker, &wallet_contract_bytes).await?; + let wallet_sk = wallet_contract.sk.clone(); + + Ok(Self { + worker, + wallet_contract, + wallet_sk, + wallet_address, + address_registrar, + wallet_contract_bytes, + }) + } + + async fn deploy_address_registrar(worker: &Worker) -> anyhow::Result { + let base_dir = Path::new(BASE_DIR) + .parent() + .unwrap() + .join("address-registrar"); + let contract_bytes = build_contract(base_dir, "eth-address-registrar").await?; + let contract = worker.dev_deploy(&contract_bytes).await?; + + // Initialize the contract + contract + .call("new") + .transact() + .await + .unwrap() + .into_result() + .unwrap(); + + // Update the file where the Wallet Contract gets the address registrar account id from + tokio::fs::write( + address_registrar_account_id_path(BASE_DIR), + contract.id().as_bytes(), + ) + .await?; + + Ok(contract) + } + + pub async fn deploy_wallet( + worker: &Worker, + contract_bytes: &[u8], + ) -> anyhow::Result<(WalletContract, Address)> { + let wallet_sk = near_crypto::SecretKey::from_random(near_crypto::KeyType::SECP256K1); + let wallet_address = { + let wallet_pk = wallet_sk.public_key(); + let hash = crate::internal::keccak256(wallet_pk.key_data()); + Address::from_slice(&hash[12..32]) + }; + let wallet_account = worker + .root_account()? + .create_subaccount(&format!("0x{}", hex::encode(wallet_address))) + .keys(SecretKey::from_random(KeyType::ED25519)) + .initial_balance(INITIAL_BALANCE) + .transact() + .await? + .result; + let wallet_contract = WalletContract { + inner: wallet_account.deploy(contract_bytes).await?.result, + sk: wallet_sk, + }; + + Ok((wallet_contract, wallet_address)) + } +} + +async fn build_contract>( + base_dir: P, + package_name: &str, +) -> anyhow::Result> { + let output = Command::new("cargo") + .env("RUSTFLAGS", "-C link-arg=-s") + .current_dir(base_dir.as_ref()) + .args(["build", "--target", "wasm32-unknown-unknown", "--release"]) + .output() + .await?; + + if !output.status.success() { + anyhow::bail!("Build failed: {}", String::from_utf8_lossy(&output.stderr)); + } + + let artifact_path = base_dir + .as_ref() + .parent() + .unwrap() + .join("target") + .join("wasm32-unknown-unknown") + .join("release") + .join([package_name.replace('-', "_").as_str(), ".wasm"].concat()); + + let bytes = tokio::fs::read(artifact_path).await?; + Ok(bytes) +} + +fn address_registrar_account_id_path(base_dir: &str) -> PathBuf { + Path::new(base_dir) + .join("src") + .join("ADDRESS_REGISTRAR_ACCOUNT_ID") +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/types.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/types.rs new file mode 100644 index 00000000000..619e10577d3 --- /dev/null +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/types.rs @@ -0,0 +1,264 @@ +use crate::{ + error::{Error, UserError}, + near_action::{ + self, AccessKey, AccessKeyPermission, AddKeyAction, DeleteKeyAction, FunctionCallAction, + FunctionCallPermission, TransferAction, + }, +}; +use ethabi::{Address, ParamType}; +use near_sdk::{AccountId, Gas, NearToken, PublicKey}; +use once_cell::sync::Lazy; + +pub const FUNCTION_CALL_SELECTOR: &[u8] = &[0x61, 0x79, 0xb7, 0x07]; +pub const FUNCTION_CALL_SIGNATURE: [ParamType; 5] = [ + ParamType::String, // receiver_id + ParamType::String, // method_name + ParamType::Bytes, // args + ParamType::Uint(64), // gas + ParamType::Uint(32), // yocto_near +]; + +pub const TRANSFER_SELECTOR: &[u8] = &[0x3e, 0xd6, 0x41, 0x24]; +pub const TRANSFER_SIGNATURE: [ParamType; 2] = [ + ParamType::String, // receiver_id + ParamType::Uint(32), // yocto_near +]; + +pub const ADD_KEY_SELECTOR: &[u8] = &[0x75, 0x3c, 0xe5, 0xab]; +// This one needs to be `Lazy` because it requires `Box` (non-const) in the `Array`. +pub static ADD_KEY_SIGNATURE: Lazy<[ParamType; 8]> = Lazy::new(|| { + [ + ParamType::Uint(8), // public_key_kind + ParamType::Bytes, // public_key + ParamType::Uint(64), // nonce + ParamType::Bool, // is_full_access + ParamType::Bool, // is_limited_allowance + ParamType::Uint(128), // allowance + ParamType::String, // receiver_id + ParamType::Array(Box::new(ParamType::String)), // method_names + ] +}); + +pub const DELETE_KEY_SELECTOR: &[u8] = &[0x3f, 0xc6, 0xd4, 0x04]; +pub const DELETE_KEY_SIGNATURE: [ParamType; 2] = [ + ParamType::Uint(8), // public_key_kind + ParamType::Bytes, // public_key +]; + +/// Response given from the `rlp_execute` entry point to the contract. +/// The error information is needed because that method is not meant to panic, +/// therefore success/failure must be communicated via the return value. +/// The reason that method should never panic is to ensure the contract's state +/// can be changed even in error cases. For example, banning a dishonest relayer. +#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)] +pub struct ExecuteResponse { + pub success: bool, + pub success_value: Option>, + pub error: Option, +} + +impl From for ExecuteResponse { + fn from(value: Error) -> Self { + Self { + success: false, + success_value: None, + error: Some(format!("{value}")), + } + } +} + +/// Struct holding environment parameters that are needed to validate transactions +/// before executing them. This struct is used in the `internal` module so that it +/// can be unit tested without mocking up the whole Near runtime. In the Wasm contract, +/// the struct is constructed via functions in `near_sdk::env`. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct ExecutionContext { + pub current_address: Address, + pub attached_deposit: NearToken, + pub predecessor_account_id: AccountId, + pub current_account_id: AccountId, +} + +impl ExecutionContext { + pub fn new( + current_account_id: AccountId, + predecessor_account_id: AccountId, + attached_deposit: NearToken, + ) -> Result { + let current_address = crate::internal::extract_address(¤t_account_id)?; + Ok(Self { + current_address, + attached_deposit, + predecessor_account_id, + current_account_id, + }) + } +} + +#[must_use] +pub enum TransactionValidationOutcome { + Validated, + AddressCheckRequired(Address), +} + +/// The Near protocol actions represented in a form that is suitable for the +/// Solidity ABI. This allows them to be encoded into the `data` field of an +/// Ethereum transaction in a way that can be parsed by Ethereum tooling. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Action { + FunctionCall { + receiver_id: String, + method_name: String, + args: Vec, + gas: u64, + yocto_near: u32, + }, + Transfer { + receiver_id: String, + yocto_near: u32, + }, + AddKey { + public_key_kind: u8, + public_key: Vec, + nonce: u64, + is_full_access: bool, + is_limited_allowance: bool, + allowance: u128, + receiver_id: String, + method_names: Vec, + }, + DeleteKey { + public_key_kind: u8, + public_key: Vec, + }, +} + +impl Action { + pub fn value(&self) -> NearToken { + match self { + Action::FunctionCall { yocto_near, .. } => { + NearToken::from_yoctonear((*yocto_near).into()) + } + Action::Transfer { yocto_near, .. } => NearToken::from_yoctonear((*yocto_near).into()), + Action::AddKey { .. } => NearToken::from_yoctonear(0), + Action::DeleteKey { .. } => NearToken::from_yoctonear(0), + } + } + + pub fn try_into_near_action( + self, + additional_value: u128, + ) -> Result { + let action = match self { + Action::FunctionCall { + receiver_id: _, + method_name, + args, + gas, + yocto_near, + } => { + let action = FunctionCallAction { + method_name, + args, + gas: Gas::from_gas(gas), + deposit: NearToken::from_yoctonear( + additional_value.saturating_add(yocto_near.into()), + ), + }; + near_action::Action::FunctionCall(action) + } + Action::Transfer { + receiver_id: _, + yocto_near, + } => { + let action = TransferAction { + deposit: NearToken::from_yoctonear( + additional_value.saturating_add(yocto_near.into()), + ), + }; + near_action::Action::Transfer(action) + } + Action::AddKey { + public_key_kind, + public_key, + nonce, + is_full_access, + is_limited_allowance, + allowance, + receiver_id, + method_names, + } => { + let public_key = construct_public_key(public_key_kind, &public_key)?; + let access_key = if is_full_access { + AccessKey { + nonce, + permission: AccessKeyPermission::FullAccess, + } + } else { + let allowance = if is_limited_allowance { + Some(allowance) + } else { + None + }; + AccessKey { + nonce, + permission: AccessKeyPermission::FunctionCall(FunctionCallPermission { + allowance: allowance.map(NearToken::from_yoctonear), + receiver_id: receiver_id + .parse() + .map_err(|_| Error::User(UserError::InvalidAccessKeyAccountId))?, + method_names, + }), + } + }; + let action = AddKeyAction { + public_key, + access_key, + }; + near_action::Action::AddKey(action) + } + Action::DeleteKey { + public_key_kind, + public_key, + } => { + let action = DeleteKeyAction { + public_key: construct_public_key(public_key_kind, &public_key)?, + }; + near_action::Action::DeleteKey(action) + } + }; + Ok(action) + } +} + +fn construct_public_key(public_key_kind: u8, public_key: &[u8]) -> Result { + if public_key_kind > 1 { + return Err(Error::User(UserError::UnknownPublicKeyKind)); + } + let mut bytes = Vec::with_capacity(public_key.len() + 1); + bytes.push(public_key_kind); + bytes.extend_from_slice(public_key); + bytes.try_into().map_err(|_| { + if public_key_kind == 0 { + Error::User(UserError::InvalidEd25519Key) + } else { + Error::User(UserError::InvalidSecp256k1Key) + } + }) +} + +#[test] +fn test_function_selectors() { + let function_call_signature = ethabi::short_signature("functionCall", &FUNCTION_CALL_SIGNATURE); + + let transfer_signature = ethabi::short_signature("transfer", &TRANSFER_SIGNATURE); + + let add_key_signature = ethabi::short_signature("addKey", ADD_KEY_SIGNATURE.as_ref()); + + let delete_key = ethabi::short_signature("deleteKey", &DELETE_KEY_SIGNATURE); + + assert_eq!(function_call_signature, FUNCTION_CALL_SELECTOR); // 0x6179b707 + assert_eq!(transfer_signature, TRANSFER_SELECTOR); // 0x3ed64124 + assert_eq!(add_key_signature, ADD_KEY_SELECTOR); // 0x753ce5ab + assert_eq!(delete_key, DELETE_KEY_SELECTOR); // 0x3fc6d404 +} diff --git a/runtime/near-wallet-contract/res/wallet_contract.wasm b/runtime/near-wallet-contract/res/wallet_contract.wasm index d82afe3cc670abdffe2ee7625c1b493cf88c4bde..8784d9a1542cedf55eb4e7da5c86108b6a28fc84 100755 GIT binary patch literal 310376 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�((IDKJAUaAT1^5Se(*3vgd59k{!gjo%iabYw!h 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 Y4msG7QkoEt@m<~3#NNrG_7E@pAA8xmCIA2c diff --git a/runtime/near-wallet-contract/wallet-contract/Cargo.lock b/runtime/near-wallet-contract/wallet-contract/Cargo.lock deleted file mode 100644 index 7184a20c2ae..00000000000 --- a/runtime/near-wallet-contract/wallet-contract/Cargo.lock +++ /dev/null @@ -1,1529 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" - -[[package]] -name = "ahash" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" -dependencies = [ - "getrandom 0.2.11", - "once_cell", - "version_check", -] - -[[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 = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "bitvec" -version = "0.20.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "blake2" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" -dependencies = [ - "crypto-mac", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[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 = "borsh" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" -dependencies = [ - "borsh-derive", - "hashbrown 0.11.2", -] - -[[package]] -name = "borsh-derive" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate 0.1.5", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytesize" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" - -[[package]] -name = "c2-chacha" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d27dae93fe7b1e0424dc57179ac396908c26b035a87234809f5c4dfd1b47dc80" -dependencies = [ - "cipher", - "ppv-lite86", -] - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.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", -] - -[[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" -dependencies = [ - "generic-array", -] - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" -dependencies = [ - "libc", -] - -[[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", - "typenum", -] - -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "curve25519-dalek" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle", - "zeroize", -] - -[[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", - "rustc_version", - "syn 1.0.109", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer 0.10.4", - "crypto-common", -] - -[[package]] -name = "dyn-clone" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" - -[[package]] -name = "easy-ext" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53aff6fdc1b181225acdcb5b14c47106726fd8e486707315b1b138baed68ee31" - -[[package]] -name = "ed25519" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" -dependencies = [ - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand 0.7.3", - "serde", - "sha2 0.9.9", - "zeroize", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fixed-hash" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" -dependencies = [ - "byteorder", - "rand 0.8.5", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - -[[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 = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "iana-time-zone" -version = "0.1.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "impl-codec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown 0.14.3", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "js-sys" -version = "0.3.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "keccak" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin", -] - -[[package]] -name = "libc" -version = "0.2.150" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "memory_units" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" - -[[package]] -name = "near-abi" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "885db39b08518fa700b73fa2214e8adbbfba316ba82dd510f50519173eadaf73" -dependencies = [ - "borsh", - "schemars", - "semver", - "serde", -] - -[[package]] -name = "near-account-id" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d258582a1878e6db67400b0504a5099db85718d22c2e07f747fe1706ae7150" -dependencies = [ - "borsh", - "serde", -] - -[[package]] -name = "near-crypto" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e75673d69fd7365508f3d32483669fe45b03bfb34e4d9363e90adae9dfb416c" -dependencies = [ - "arrayref", - "blake2", - "borsh", - "bs58", - "c2-chacha", - "curve25519-dalek", - "derive_more", - "ed25519-dalek", - "near-account-id", - "once_cell", - "parity-secp256k1", - "primitive-types", - "rand 0.7.3", - "rand_core 0.5.1", - "serde", - "serde_json", - "subtle", - "thiserror", -] - -[[package]] -name = "near-primitives" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad1a9a1640539c81f065425c31bffcfbf6b31ef1aeaade59ce905f5df6ac860" -dependencies = [ - "borsh", - "byteorder", - "bytesize", - "chrono", - "derive_more", - "easy-ext", - "hex", - "near-crypto", - "near-primitives-core", - "near-rpc-error-macro", - "near-vm-errors", - "num-rational", - "once_cell", - "primitive-types", - "rand 0.7.3", - "reed-solomon-erasure", - "serde", - "serde_json", - "smart-default", - "strum", - "thiserror", -] - -[[package]] -name = "near-primitives-core" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d508f0fc340f6461e4e256417685720d3c4c00bb5a939b105160e49137caba" -dependencies = [ - "base64 0.11.0", - "borsh", - "bs58", - "derive_more", - "near-account-id", - "num-rational", - "serde", - "sha2 0.10.8", - "strum", -] - -[[package]] -name = "near-rpc-error-core" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ee0b41c75ef859c193a8ff1dadfa0c8207bc0ac447cc22259721ad769a1408" -dependencies = [ - "quote", - "serde", - "syn 1.0.109", -] - -[[package]] -name = "near-rpc-error-macro" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e837bd4bacd807073ec5ceb85708da7f721b46a4c2a978de86027fb0034ce31" -dependencies = [ - "near-rpc-error-core", - "serde", - "syn 1.0.109", -] - -[[package]] -name = "near-sdk" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15eb3de2defe3626260cc209a6cdb985c6b27b0bd4619fad97dcfae002c3c5bd" -dependencies = [ - "base64 0.13.1", - "borsh", - "bs58", - "near-abi", - "near-crypto", - "near-primitives", - "near-primitives-core", - "near-sdk-macros", - "near-sys", - "near-vm-logic", - "once_cell", - "schemars", - "serde", - "serde_json", - "wee_alloc", -] - -[[package]] -name = "near-sdk-macros" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4907affc9f5ed559456509188ff0024f1f2099c0830e6bdb66eb61d5b75912c0" -dependencies = [ - "Inflector", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "near-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397688591acf8d3ebf2c2485ba32d4b24fc10aad5334e3ad8ec0b7179bfdf06b" - -[[package]] -name = "near-vm-errors" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0da466a30f0446639cbd788c30865086fac3e8dcb07a79e51d2b0775ed4261e" -dependencies = [ - "borsh", - "near-account-id", - "near-rpc-error-macro", - "serde", -] - -[[package]] -name = "near-vm-logic" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b534828419bacbf1f7b11ef7b00420f248c548c485d3f0cfda8bb6931152f2" -dependencies = [ - "base64 0.13.1", - "borsh", - "bs58", - "byteorder", - "near-account-id", - "near-crypto", - "near-primitives", - "near-primitives-core", - "near-vm-errors", - "ripemd", - "serde", - "sha2 0.10.8", - "sha3", - "zeropool-bn", -] - -[[package]] -name = "num-bigint" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[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-rational" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits", - "serde", -] - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "parity-scale-codec" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" -dependencies = [ - "arrayvec 0.7.4", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "parity-secp256k1" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fca4f82fccae37e8bbdaeb949a4a218a1bbc485d11598f193d2a908042e5fc1" -dependencies = [ - "arrayvec 0.5.2", - "cc", - "cfg-if 0.1.10", - "rand 0.7.3", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "primitive-types" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" -dependencies = [ - "fixed-hash", - "impl-codec", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - -[[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", -] - -[[package]] -name = "proc-macro2" -version = "1.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" - -[[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", -] - -[[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.11", -] - -[[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 = "reed-solomon-erasure" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a415a013dd7c5d4221382329a5a3482566da675737494935cbbbcdec04662f9d" -dependencies = [ - "smallvec", -] - -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "rlp" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1190dcc8c3a512f1eef5d09bb8c84c7f39e1054e174d1795482e18f5272f2e73" -dependencies = [ - "rustc-hex", -] - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[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.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "schemars" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" -dependencies = [ - "dyn-clone", - "schemars_derive", - "serde", - "serde_json", -] - -[[package]] -name = "schemars_derive" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 1.0.109", -] - -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" - -[[package]] -name = "serde" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - -[[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", - "syn 1.0.109", -] - -[[package]] -name = "serde_json" -version = "1.0.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest 0.10.7", - "keccak", -] - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" - -[[package]] -name = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - -[[package]] -name = "smart-default" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "thiserror" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wallet-contract" -version = "0.1.0" -dependencies = [ - "hex", - "near-sdk", - "rlp", - "serde_json", -] - -[[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.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" -dependencies = [ - "cfg-if 1.0.0", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.39", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" - -[[package]] -name = "wee_alloc" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "memory_units", - "winapi", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[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_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[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_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[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_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "winnow" -version = "0.5.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff" -dependencies = [ - "memchr", -] - -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - -[[package]] -name = "zeroize" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" -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", - "syn 2.0.39", -] - -[[package]] -name = "zeropool-bn" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e61de68ede9ffdd69c01664f65a178c5188b73f78faa21f0936016a888ff7c" -dependencies = [ - "borsh", - "byteorder", - "crunchy", - "lazy_static", - "rand 0.8.5", - "rustc-hex", -] diff --git a/runtime/near-wallet-contract/wallet-contract/Cargo.toml b/runtime/near-wallet-contract/wallet-contract/Cargo.toml deleted file mode 100644 index a7c0259d244..00000000000 --- a/runtime/near-wallet-contract/wallet-contract/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "wallet-contract" -version = "0.1.0" -publish = false -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -hex = "0.4.2" -serde_json = "1.0.68" -near-sdk = "4.1.1" -rlp = "0.4.6" - -[profile.release] -codegen-units = 1 -# Tell `rustc` to optimize for small code size. -opt-level = "z" -strip = true -lto = true -debug = false -panic = "abort" -rpath = false -debug-assertions = false -incremental = false -overflow-checks = true - -[workspace] -members = [] diff --git a/runtime/near-wallet-contract/wallet-contract/src/lib.rs b/runtime/near-wallet-contract/wallet-contract/src/lib.rs deleted file mode 100644 index 193e0942cc9..00000000000 --- a/runtime/near-wallet-contract/wallet-contract/src/lib.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Temporary implementation of the Wallet Contract. -//! See https://github.com/near/NEPs/issues/518. -//! Must not use in production! -// TODO(eth-implicit) Change to a real Wallet Contract implementation. - -use hex; -use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; -use near_sdk::{env, near_bindgen, AccountId, Promise}; -use rlp::Rlp; - -#[near_bindgen] -#[derive(Default, BorshDeserialize, BorshSerialize)] -pub struct WalletContract {} - -#[near_bindgen] -impl WalletContract { - /// For the sake of this placeholder implementation, we assume simplified version of the `rlp_transaction` - /// that only has 3 values: `To`, `Value`, and `PublicKey`. We assume this is a transfer transaction. - /// The real implementation would obtain the public key from `Signature`. - pub fn execute_rlp(&self, target: AccountId, rlp_transaction: Vec) { - let rlp = Rlp::new(&rlp_transaction); - - let to: String = match rlp.val_at(0) { - Ok(to) => to, - _ => env::panic_str("Missing `to` field in RLP-encoded transaction."), - }; - if target.to_string() != to { - env::panic_str("`target` not equal to transaction's `To` address."); - } - - let value_bytes: Vec = match rlp.val_at(1) { - Ok(value_bytes) => value_bytes, - _ => env::panic_str("Missing `value` field in RLP-encoded transaction."), - }; - let value = u128::from_be_bytes( - value_bytes.try_into().expect("Incorrect `value` field in RLP-encoded transaction."), - ); - - let signer_public_key_bytes: Vec = match rlp.val_at(2) { - Ok(signer_public_key_bytes) => signer_public_key_bytes, - _ => env::panic_str("Signature extraction failed for RLP-encoded transaction."), - }; - - let hash = env::keccak256(&signer_public_key_bytes); - let signer_address = format!("0x{}", hex::encode(&hash[12..32])); - - if signer_address != env::current_account_id().to_string() { - env::panic_str("Public key does not match the Wallet Contract address."); - } - - Promise::new(target).transfer(value); - } -} From abfc04b94401aa8c07a0c6a5c161b65a05408a35 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Wed, 20 Mar 2024 21:48:43 +0100 Subject: [PATCH 02/10] Integration test for wallet contract on eth implicit accounts --- Cargo.lock | 671 ++++++++++++++++-- Cargo.toml | 3 + integration-tests/Cargo.toml | 4 + .../tests/client/features/wallet_contract.rs | 368 +++++++--- 4 files changed, 893 insertions(+), 153 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a2d6d05f836..6c59f4345b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -434,6 +434,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "assert_matches" version = "1.5.0" @@ -489,6 +495,83 @@ dependencies = [ "wildmatch", ] +[[package]] +name = "aurora-engine-modexp" +version = "1.0.0" +source = "git+https://github.com/aurora-is-near/aurora-engine.git?tag=3.6.1#26a126231e1ce338598a7d9909779f32e4dce8a2" +dependencies = [ + "hex", + "num", +] + +[[package]] +name = "aurora-engine-precompiles" +version = "1.0.0" +source = "git+https://github.com/aurora-is-near/aurora-engine.git?tag=3.6.1#26a126231e1ce338598a7d9909779f32e4dce8a2" +dependencies = [ + "aurora-engine-modexp", + "aurora-engine-sdk", + "aurora-engine-types", + "ethabi", + "evm", + "hex", + "libsecp256k1", + "num", + "ripemd", + "sha2 0.10.6", + "sha3", + "zeropool-bn", +] + +[[package]] +name = "aurora-engine-sdk" +version = "1.0.0" +source = "git+https://github.com/aurora-is-near/aurora-engine.git?tag=3.6.1#26a126231e1ce338598a7d9909779f32e4dce8a2" +dependencies = [ + "aurora-engine-types", + "base64 0.21.0", + "sha2 0.10.6", + "sha3", +] + +[[package]] +name = "aurora-engine-transactions" +version = "1.0.0" +source = "git+https://github.com/aurora-is-near/aurora-engine.git?tag=3.6.1#26a126231e1ce338598a7d9909779f32e4dce8a2" +dependencies = [ + "aurora-engine-precompiles", + "aurora-engine-sdk", + "aurora-engine-types", + "evm", + "rlp", +] + +[[package]] +name = "aurora-engine-types" +version = "1.0.0" +source = "git+https://github.com/aurora-is-near/aurora-engine.git?tag=3.6.1#26a126231e1ce338598a7d9909779f32e4dce8a2" +dependencies = [ + "base64 0.21.0", + "borsh 0.10.3", + "bs58 0.5.1", + "hex", + "primitive-types 0.12.2", + "rlp", + "serde", + "serde_json", +] + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -684,7 +767,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b64485778c4f16a6a5a9d335e80d449ac6c70cdd6a06d2af18a6f6f775a125b3" dependencies = [ "arrayref", - "arrayvec", + "arrayvec 0.5.2", "cc", "cfg-if 0.1.10", "constant_time_eq", @@ -692,6 +775,15 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.5", +] + [[package]] name = "block-buffer" version = "0.10.2" @@ -805,6 +897,16 @@ dependencies = [ "hashbrown 0.11.2", ] +[[package]] +name = "borsh" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive 0.10.3", + "hashbrown 0.11.2", +] + [[package]] name = "borsh" version = "1.0.0" @@ -821,8 +923,21 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", + "borsh-derive-internal 0.9.3", + "borsh-schema-derive-internal 0.9.3", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.103", +] + +[[package]] +name = "borsh-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +dependencies = [ + "borsh-derive-internal 0.10.3", + "borsh-schema-derive-internal 0.10.3", "proc-macro-crate 0.1.5", "proc-macro2", "syn 1.0.103", @@ -853,6 +968,17 @@ dependencies = [ "syn 1.0.103", ] +[[package]] +name = "borsh-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.103", +] + [[package]] name = "borsh-schema-derive-internal" version = "0.9.3" @@ -864,6 +990,17 @@ dependencies = [ "syn 1.0.103", ] +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.103", +] + [[package]] name = "brotli" version = "3.3.4" @@ -891,12 +1028,28 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "sha2 0.10.6", + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "bytecheck" version = "0.6.8" @@ -1813,7 +1966,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ - "block-buffer", + "block-buffer 0.10.2", "crypto-common", "subtle", ] @@ -1933,7 +2086,7 @@ dependencies = [ "curve25519-dalek", "ed25519", "rand_core 0.6.4", - "sha2", + "sha2 0.10.6", "subtle", ] @@ -2063,6 +2216,114 @@ dependencies = [ "xshell", ] +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash 0.8.0", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89fb87a9e103f71b903b80b670200b54cc67a07578f070681f1fffb7396fb7" +dependencies = [ + "bytes", + "ethereum-types", + "hash-db", + "hash256-std-hasher", + "rlp", + "sha3", + "triehash", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash 0.8.0", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types 0.12.2", + "scale-info", + "uint", +] + +[[package]] +name = "evm" +version = "0.39.1" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.39.1#0334a09d6b6e83ff3a8da992e33f29ba95e0c9fe" +dependencies = [ + "auto_impl", + "ethereum", + "evm-core", + "evm-gasometer", + "evm-runtime", + "log", + "primitive-types 0.12.2", + "rlp", + "sha3", +] + +[[package]] +name = "evm-core" +version = "0.39.1" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.39.1#0334a09d6b6e83ff3a8da992e33f29ba95e0c9fe" +dependencies = [ + "primitive-types 0.12.2", +] + +[[package]] +name = "evm-gasometer" +version = "0.39.1" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.39.1#0334a09d6b6e83ff3a8da992e33f29ba95e0c9fe" +dependencies = [ + "evm-core", + "evm-runtime", + "primitive-types 0.12.2", +] + +[[package]] +name = "evm-runtime" +version = "0.39.1" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.39.1#0334a09d6b6e83ff3a8da992e33f29ba95e0c9fe" +dependencies = [ + "auto_impl", + "evm-core", + "primitive-types 0.12.2", + "sha3", +] + [[package]] name = "expect-test" version = "1.3.0" @@ -2134,6 +2395,18 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -2447,6 +2720,21 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "hash-db" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" + +[[package]] +name = "hash256-std-hasher" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" +dependencies = [ + "crunchy", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -2566,7 +2854,17 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" dependencies = [ - "hmac", + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", ] [[package]] @@ -2578,6 +2876,17 @@ dependencies = [ "digest 0.10.6", ] +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array 0.14.5", + "hmac 0.8.1", +] + [[package]] name = "http" version = "0.2.7" @@ -2715,6 +3024,44 @@ dependencies = [ "version_check", ] +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.103", +] + [[package]] name = "indexer-example" version = "0.0.0" @@ -2789,12 +3136,15 @@ dependencies = [ "actix-rt", "anyhow", "assert_matches", + "aurora-engine-transactions", + "aurora-engine-types", "borsh 1.0.0", "bytesize", "chrono", "clap", "derive-enum-from-into", "derive_more", + "ethabi", "futures", "hex", "insta", @@ -2829,11 +3179,12 @@ dependencies = [ "node-runtime", "once_cell", "parking_lot 0.12.1", - "primitive-types", + "primitive-types 0.10.1", "rand", "rlp", "serde", "serde_json", + "sha3", "smart-default", "strum", "tempfile", @@ -3011,6 +3362,54 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64 0.13.0", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + [[package]] name = "libsqlite3-sys" version = "0.26.0" @@ -3414,7 +3813,7 @@ dependencies = [ "near-crypto", "near-primitives", "near-primitives-core", - "num-rational", + "num-rational 0.3.2", "serde", "serde_json", "tempfile", @@ -3493,9 +3892,9 @@ dependencies = [ "near-store", "near-vm-runner", "node-runtime", - "num-rational", + "num-rational 0.3.2", "once_cell", - "primitive-types", + "primitive-types 0.10.1", "rand", "rand_chacha", "rayon", @@ -3521,11 +3920,11 @@ dependencies = [ "near-o11y", "near-parameters", "near-primitives", - "num-rational", + "num-rational 0.3.2", "once_cell", "serde", "serde_json", - "sha2", + "sha2 0.10.6", "smart-default", "time", "tracing", @@ -3623,7 +4022,7 @@ dependencies = [ "near-store", "near-telemetry", "near-vm-runner", - "num-rational", + "num-rational 0.3.2", "once_cell", "percent-encoding", "rand", @@ -3681,7 +4080,7 @@ dependencies = [ "blake2", "bolero", "borsh 1.0.0", - "bs58", + "bs58 0.4.0", "curve25519-dalek", "derive_more", "ed25519-dalek", @@ -3691,11 +4090,11 @@ dependencies = [ "near-config-utils", "near-stdx", "once_cell", - "primitive-types", + "primitive-types 0.10.1", "secp256k1", "serde", "serde_json", - "sha2", + "sha2 0.10.6", "subtle", "tempfile", "thiserror", @@ -3754,9 +4153,9 @@ dependencies = [ "near-o11y", "near-primitives", "near-store", - "num-rational", + "num-rational 0.3.2", "once_cell", - "primitive-types", + "primitive-types 0.10.1", "rand", "rand_hc", "serde_json", @@ -3873,7 +4272,7 @@ dependencies = [ "actix", "actix-cors", "actix-web", - "bs58", + "bs58 0.4.0", "derive_more", "easy-ext", "futures", @@ -3996,7 +4395,7 @@ dependencies = [ "anyhow", "async-trait", "borsh 1.0.0", - "bs58", + "bs58 0.4.0", "clap", "ed25519-dalek", "hex", @@ -4024,7 +4423,7 @@ dependencies = [ "secp256k1", "serde", "serde_json", - "sha2", + "sha2 0.10.6", "strum", "thiserror", "tokio", @@ -4073,7 +4472,7 @@ dependencies = [ "rayon", "rlimit", "serde", - "sha2", + "sha2 0.10.6", "smart-default", "strum", "stun", @@ -4128,7 +4527,7 @@ dependencies = [ "insta", "near-account-id", "near-primitives-core", - "num-rational", + "num-rational 0.3.2", "serde", "serde_repr", "serde_yaml", @@ -4219,9 +4618,9 @@ dependencies = [ "near-rpc-error-macro", "near-stdx", "near-vm-runner", - "num-rational", + "num-rational 0.3.2", "once_cell", - "primitive-types", + "primitive-types 0.10.1", "rand", "rand_chacha", "reed-solomon-erasure", @@ -4243,17 +4642,17 @@ dependencies = [ "arbitrary", "base64 0.21.0", "borsh 1.0.0", - "bs58", + "bs58 0.4.0", "derive_more", "enum-map", "expect-test", "insta", "near-account-id", - "num-rational", + "num-rational 0.3.2", "serde", "serde_json", "serde_repr", - "sha2", + "sha2 0.10.6", "thiserror", ] @@ -4325,7 +4724,7 @@ dependencies = [ "near-ping", "near-primitives", "once_cell", - "sha2", + "sha2 0.10.6", "tokio", "tracing", ] @@ -4548,7 +4947,7 @@ dependencies = [ "near-vm-engine", "near-vm-types", "near-vm-vm", - "num-rational", + "num-rational 0.3.2", "once_cell", "parity-wasm 0.41.0", "parity-wasm 0.42.2", @@ -4560,7 +4959,7 @@ dependencies = [ "serde", "serde_json", "serde_repr", - "sha2", + "sha2 0.10.6", "sha3", "strum", "tempfile", @@ -4729,9 +5128,9 @@ dependencies = [ "near-telemetry", "near-vm-runner", "node-runtime", - "num-rational", + "num-rational 0.3.2", "once_cell", - "primitive-types", + "primitive-types 0.10.1", "rand", "rayon", "regex", @@ -4843,14 +5242,14 @@ dependencies = [ "near-vm-runner", "near-wallet-contract", "num-bigint 0.3.3", - "num-rational", + "num-rational 0.3.2", "num-traits", "once_cell", "rand", "rayon", "serde", "serde_json", - "sha2", + "sha2 0.10.6", "tempfile", "testlib", "thiserror", @@ -4886,6 +5285,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint 0.4.3", + "num-complex", + "num-integer", + "num-iter", + "num-rational 0.4.1", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.2.6" @@ -4908,6 +5321,26 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -4918,6 +5351,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.3.2" @@ -4931,6 +5375,18 @@ dependencies = [ "serde", ] +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint 0.4.3", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -5196,6 +5652,32 @@ dependencies = [ "syn 1.0.103", ] +[[package]] +name = "parity-scale-codec" +version = "3.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" +dependencies = [ + "arrayvec 0.7.4", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.2", + "proc-macro2", + "quote", + "syn 1.0.103", +] + [[package]] name = "parity-wasm" version = "0.41.0" @@ -5426,7 +5908,21 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" dependencies = [ - "fixed-hash", + "fixed-hash 0.7.0", + "uint", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash 0.8.0", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", "uint", ] @@ -5446,7 +5942,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit 0.20.2", ] [[package]] @@ -5993,9 +6499,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", + "rlp-derive", "rustc-hex", ] +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.103", +] + [[package]] name = "rocksdb" version = "0.21.0" @@ -6012,7 +6530,7 @@ version = "0.0.0" dependencies = [ "anyhow", "borsh 1.0.0", - "bs58", + "bs58 0.4.0", "bytesize", "cfg-if 1.0.0", "chrono", @@ -6033,7 +6551,7 @@ dependencies = [ "near-vm-runner", "nearcore", "node-runtime", - "num-rational", + "num-rational 0.3.2", "num-traits", "rand", "rand_xorshift", @@ -6121,7 +6639,7 @@ dependencies = [ "block_on_proc", "cfg-if 1.0.0", "hex", - "hmac", + "hmac 0.12.1", "http", "log", "maybe-async", @@ -6132,7 +6650,7 @@ dependencies = [ "serde", "serde-xml-rs", "serde_derive", - "sha2", + "sha2 0.10.6", "thiserror", "time", "tokio", @@ -6257,6 +6775,30 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scale-info" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef2175c2907e7c8bc0a9c3f86aeb5ec1f3b275300ad58a44d0c3ae379a5e52e" +dependencies = [ + "cfg-if 1.0.0", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b8eb8fd61c5cdd3390d9b2132300a7e7618955b98b8416f118c1b4e144f" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.103", +] + [[package]] name = "schannel" version = "0.1.19" @@ -6526,6 +7068,19 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + [[package]] name = "sha2" version = "0.10.6" @@ -7058,6 +7613,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -7211,6 +7775,17 @@ dependencies = [ "winnow", ] +[[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", + "toml_datetime", + "winnow", +] + [[package]] name = "tonic" version = "0.6.2" @@ -7414,6 +7989,16 @@ dependencies = [ "tracing-log 0.2.0", ] +[[package]] +name = "triehash" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1631b201eb031b563d2e85ca18ec8092508e262a3196ce9bd10a67ec87b9f5c" +dependencies = [ + "hash-db", + "rlp", +] + [[package]] name = "try-lock" version = "0.2.3" @@ -7468,9 +8053,9 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "uint" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ "byteorder", "crunchy", diff --git a/Cargo.toml b/Cargo.toml index 73ed4457d5d..9d3ff61ee53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -121,6 +121,8 @@ arbitrary = { version = "1.2.3", features = ["derive"] } arc-swap = "1.5" assert_matches = "1.5.0" async-trait = "0.1.58" +aurora-engine-transactions = { git = "https://github.com/aurora-is-near/aurora-engine.git", tag = "3.6.1" } +aurora-engine-types = { git = "https://github.com/aurora-is-near/aurora-engine.git", tag = "3.6.1" } awc = { version = "3", features = ["openssl"] } backtrace = "0.3" base64 = "0.21" @@ -170,6 +172,7 @@ ed25519-dalek = { version = "2.1.0", default-features = false, features = [ elastic-array = "0.11" enum-map = "2.1.0" enumset = "1.0" +ethabi = "18" expect-test = "1.3.0" finite-wasm = "0.5.0" fs2 = "0.4" diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 94bcc438f73..2f3606f20ce 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -67,10 +67,14 @@ testlib.workspace = true [dev-dependencies] assert_matches.workspace = true +aurora-engine-transactions.workspace = true +aurora-engine-types.workspace = true derive-enum-from-into.workspace = true +ethabi.workspace = true insta.workspace = true near-undo-block.workspace = true rlp.workspace = true +sha3.workspace = true [features] performance_stats = [ diff --git a/integration-tests/src/tests/client/features/wallet_contract.rs b/integration-tests/src/tests/client/features/wallet_contract.rs index 9666c2a61a5..2f1a8b6bd22 100644 --- a/integration-tests/src/tests/client/features/wallet_contract.rs +++ b/integration-tests/src/tests/client/features/wallet_contract.rs @@ -1,12 +1,15 @@ use assert_matches::assert_matches; +use aurora_engine_transactions::eip_2930::Transaction2930; +use aurora_engine_transactions::EthTransactionKind; +use aurora_engine_types::types::{Address, Wei}; +use ethabi::ethereum_types::U256; use near_chain_configs::{Genesis, NEAR_BASE}; use near_client::{test_utils::TestEnv, ProcessTxResponse}; -use near_crypto::{InMemorySigner, KeyType, SecretKey}; -use near_primitives::errors::{ - ActionError, ActionErrorKind, FunctionCallError, InvalidAccessKeyError, InvalidTxError, - TxExecutionError, -}; -use near_primitives::test_utils::eth_implicit_test_account; +use near_crypto::{InMemorySigner, KeyType, PublicKey, SecretKey}; +use near_primitives::account::id::AccountIdRef; +use near_primitives::account::{AccessKeyPermission, FunctionCallPermission}; +use near_primitives::errors::{InvalidAccessKeyError, InvalidTxError}; +use near_primitives::test_utils::{create_user_test_signer, eth_implicit_test_account}; use near_primitives::transaction::{ Action, AddKeyAction, DeployContractAction, FunctionCallAction, SignedTransaction, TransferAction, @@ -23,13 +26,9 @@ use near_vm_runner::ContractCode; use near_wallet_contract::{wallet_contract, wallet_contract_magic_bytes}; use nearcore::test_utils::TestEnvNightshadeSetupExt; use node_runtime::ZERO_BALANCE_ACCOUNT_STORAGE_LIMIT; -use rlp::RlpStream; -use testlib::runtime_utils::{alice_account, bob_account, carol_account}; +use testlib::runtime_utils::{alice_account, bob_account}; -use crate::{ - node::{Node, RuntimeNode}, - tests::client::process_blocks::produce_blocks_from_height, -}; +use crate::tests::client::process_blocks::produce_blocks_from_height; /// Try to process tx in the next blocks, check that tx and all generated receipts succeed. /// Return height of the next block. @@ -43,6 +42,7 @@ fn check_tx_processing( assert_eq!(env.clients[0].process_tx(tx, false, false), ProcessTxResponse::ValidTx); let next_height = produce_blocks_from_height(env, blocks_number, height); let final_outcome = env.clients[0].chain.get_final_transaction_result(&tx_hash).unwrap(); + println!("{final_outcome:?}"); assert_matches!(final_outcome.status, FinalExecutionStatus::SuccessValue(_)); next_height } @@ -65,6 +65,22 @@ fn view_request(env: &TestEnv, request: QueryRequest) -> QueryResponse { .unwrap() } +fn view_balance(env: &TestEnv, account: &AccountIdRef) -> u128 { + let request = QueryRequest::ViewAccount { account_id: account.into() }; + match view_request(&env, request).kind { + QueryResponseKind::ViewAccount(view) => view.amount, + _ => panic!("wrong query response"), + } +} + +fn view_nonce(env: &TestEnv, account: &AccountIdRef, pk: PublicKey) -> u64 { + let request = QueryRequest::ViewAccessKey { account_id: account.into(), public_key: pk }; + match view_request(&env, request).kind { + QueryResponseKind::AccessKey(view) => view.nonce, + _ => panic!("wrong query response"), + } +} + /// Tests that ETH-implicit account is created correctly, with Wallet Contract hash. #[test] fn test_eth_implicit_account_creation() { @@ -214,126 +230,258 @@ fn test_transaction_from_eth_implicit_account_fail() { assert_eq!(response, expected_tx_error); } -// TODO(eth-implicit) Remove this test and replace it with tests that directly call the `Wallet Contract` when it is ready. -/// Creating an ETH-implicit account with meta-transaction, then attempting to use it with another meta-transaction. -/// -/// The `create_account` parameter controls whether we create ETH-implicit account -/// before attempting to use it by making a function call. -/// Depending on `rlp_transaction` blob that is sent to the `Wallet Contract` -/// the transaction is either authorized or unauthorized. -/// The `authorized` parameter controls which case will be tested. -fn meta_tx_call_wallet_contract(create_account: bool, authorized: bool) { +#[test] +fn test_wallet_contract_interaction() { if !checked_feature!("stable", EthImplicitAccounts, PROTOCOL_VERSION) { return; } - let genesis = Genesis::test(vec![alice_account(), bob_account(), carol_account()], 3); + + let genesis = Genesis::test(vec!["test0".parse().unwrap(), alice_account(), bob_account()], 1); + let mut env = TestEnv::builder(&genesis.config).nightshade_runtimes(&genesis).build(); + + let genesis_block = env.clients[0].chain.get_block_by_height(0).unwrap(); + let mut height = 1; + let blocks_number = 10; + + // As the relayer, alice will be sending Near transactions which + // contain the Ethereum transactions the user signs. let relayer = alice_account(); - let node = RuntimeNode::new_from_genesis(&relayer, genesis); - let sender = bob_account(); + let mut relayer_signer = + NearSigner { account_id: &relayer, signer: create_user_test_signer(&relayer) }; + // Bob will receive a $NEAR transfer from the eth implicit account + let receiver = bob_account(); + // Generate an eth implicit account for the user let secret_key = SecretKey::from_seed(KeyType::SECP256K1, "test"); let public_key = secret_key.public_key(); let eth_implicit_account = derive_eth_implicit_account_id(public_key.unwrap_as_secp256k1()); - let other_public_key = SecretKey::from_seed(KeyType::SECP256K1, "test2").public_key(); - - // Although ETH-implicit account can be zero-balance, we pick 1 here in order to make transfer later from this account. - let transfer_amount = 1u128; - let actions = vec![Action::Transfer(TransferAction { deposit: transfer_amount })]; - - if create_account { - // Create ETH-implicit account by funding it. - node.user() - .meta_tx(sender.clone(), eth_implicit_account.clone(), relayer.clone(), actions) - .unwrap() - .assert_success(); - } - let target = carol_account(); - let initial_balance = node.view_balance(&target).expect("failed looking up balance"); - - // TODO(eth-implicit) Append appropriate values to the RLP stream when proper `Wallet Contract` is implemented. - let mut stream = RlpStream::new_list(3); - stream.append(&target.as_str()); - // The RLP trait `Encodable` is not implemented for `u128`. We must encode it as bytes. - // TODO(eth-implicit) Do not try to encode `u128` values directly, see https://github.com/near/nearcore/pull/10269#discussion_r1425585051. - stream.append(&transfer_amount.to_be_bytes().as_slice()); - if authorized { - stream.append(&public_key.key_data()); - } else { - stream.append(&other_public_key.key_data()); - } - let rlp_encoded_data = stream.out().to_vec(); + // Create ETH-implicit account by funding it. + // Although ETH-implicit account can be zero-balance, we pick a non-zero amount + // here in order to make transfer later from this account. + let deposit_for_account_creation = NEAR_BASE; + let actions = vec![Action::Transfer(TransferAction { deposit: deposit_for_account_creation })]; + let nonce = + view_nonce(&env, relayer_signer.account_id, relayer_signer.signer.public_key.clone()) + 1; + let block_hash = *genesis_block.hash(); + let signed_transaction = SignedTransaction::from_actions( + nonce, + relayer.clone(), + eth_implicit_account.clone(), + &relayer_signer.signer, + actions, + block_hash, + ); + height = check_tx_processing(&mut env, signed_transaction, height, blocks_number); - let args = serde_json::json!({ - "target": target.to_string(), - "rlp_transaction": rlp_encoded_data, - }) - .to_string() + // The relayer adds its key to the eth implicit account so that + // can sign Near transactions for the user. + let relayer_pk = relayer_signer.signer.public_key.clone(); + let action = Action::AddKey(Box::new(AddKeyAction { + public_key: relayer_pk, + access_key: AccessKey { + nonce: 0, + permission: AccessKeyPermission::FunctionCall(FunctionCallPermission { + allowance: None, + receiver_id: eth_implicit_account.to_string(), + method_names: vec!["rlp_execute".into()], + }), + }, + })); + let signed_transaction = create_rlp_execute_tx( + ð_implicit_account, + action, + 0, + ð_implicit_account, + &secret_key, + &mut relayer_signer, + &env, + ); + height = check_tx_processing(&mut env, signed_transaction, height, blocks_number); + + // Now the relayer can sign transactions for the implicit account directly + relayer_signer.account_id = ð_implicit_account; + + let init_wallet_balance = view_balance(&env, ð_implicit_account); + let init_receiver_balance = view_balance(&env, &receiver); + + // The user signs a transaction to transfer some $NEAR + let transfer_amount = NEAR_BASE / 7; + let action = Action::Transfer(TransferAction { deposit: transfer_amount }); + let signed_transaction = create_rlp_execute_tx( + &receiver, + action, + 1, + ð_implicit_account, + &secret_key, + &mut relayer_signer, + &env, + ); + check_tx_processing(&mut env, signed_transaction, height, blocks_number); + + let final_wallet_balance = view_balance(&env, ð_implicit_account); + let final_receiver_balance = view_balance(&env, &receiver); + + assert_eq!(final_receiver_balance - init_receiver_balance, transfer_amount); + let wallet_balance_diff = init_wallet_balance - final_wallet_balance; + // Wallet balance is a little lower due to gas fees. + assert!(wallet_balance_diff - transfer_amount < NEAR_BASE / 500); +} + +fn create_rlp_execute_tx( + target: &AccountIdRef, + mut action: Action, + nonce: u64, + eth_implicit_account: &AccountIdRef, + secret_key: &SecretKey, + near_signer: &mut NearSigner<'_>, + env: &TestEnv, +) -> SignedTransaction { + const CHAIN_ID: u64 = 0x4ea7; + // handles 24 vs 18 decimal mismatch between $NEAR and $ETH + const MAX_YOCTO_NEAR: u128 = 1_000_000; + + // Construct Eth transaction from user's intended action + let value = match &mut action { + Action::Transfer(tx) => { + let raw_amount = tx.deposit; + tx.deposit = raw_amount % MAX_YOCTO_NEAR; + Wei::new_u128(raw_amount / MAX_YOCTO_NEAR) + } + Action::FunctionCall(fn_call) => { + let raw_amount = fn_call.deposit; + fn_call.deposit = raw_amount % MAX_YOCTO_NEAR; + Wei::new_u128(raw_amount / MAX_YOCTO_NEAR) + } + _ => Wei::zero(), + }; + let tx_data = abi_encode(target.to_string(), action); + let transaction = Transaction2930 { + chain_id: CHAIN_ID, + nonce: nonce.into(), + gas_price: U256::zero(), + gas_limit: U256::zero(), + to: Some(derive_address(target)), + value, + data: tx_data, + access_list: Vec::new(), + }; + let signed_tx = sign_eth_transaction(transaction, &secret_key); + let signed_tx_bytes: Vec = (&signed_tx).into(); + let tx_bytes_b64 = near_primitives::serialize::to_base64(&signed_tx_bytes); + let args = format!( + r#"{{ + "target": "{target}", + "tx_bytes_b64": "{tx_bytes_b64}" + }}"# + ) .into_bytes(); + // Construct Near transaction to `rlp_execute` method let actions = vec![Action::FunctionCall(Box::new(FunctionCallAction { - method_name: "execute_rlp".to_owned(), + method_name: "rlp_execute".into(), args, - gas: 30_000_000_000_000, + gas: 300_000_000_000_000, deposit: 0, }))]; - // Call Wallet Contract with JSON-encoded arguments: `target` and `rlp_transaction`. The `rlp_transaction`'s value is RLP-encoded. - let tx_result = - node.user().meta_tx(sender, eth_implicit_account.clone(), relayer, actions).unwrap(); - let wallet_contract_call_result = &tx_result.receipts_outcome[1].outcome.status; - - if create_account && authorized { - // If the public key recovered from the RLP transaction's signature is valid for this ETH-implicit account, - // the transaction will succeed. `target`'s balance will increase by `transfer_amount`. - tx_result.assert_success(); - let final_balance = node.view_balance(&target).expect("failed looking up balance"); - assert_eq!(final_balance, initial_balance + transfer_amount); - return; - } + let nonce = view_nonce(env, near_signer.account_id, near_signer.signer.public_key.clone()) + 1; + let block_hash = *env.clients[0].chain.get_head_block().unwrap().hash(); + SignedTransaction::from_actions( + nonce, + near_signer.account_id.into(), + eth_implicit_account.into(), + &near_signer.signer, + actions, + block_hash, + ) +} - if create_account { - // The public key recovered from the RLP transaction's signature isn't valid for this ETH-implicit account. - // The Wallet Contract will reject this transaction. - let expected_error = near_primitives::views::ExecutionStatusView::Failure( - TxExecutionError::ActionError( - ActionError { - index: Some(0), - kind: ActionErrorKind::FunctionCallError { - 0: FunctionCallError::ExecutionError( - "Smart contract panicked: Public key does not match the Wallet Contract address." - .to_string() - ) - } - } - ) - ); - assert_eq!(wallet_contract_call_result, &expected_error); - } else { - // The Wallet Contract function call is not executed because the account does not exist. - let expected_error = near_primitives::views::ExecutionStatusView::Failure( - TxExecutionError::ActionError(ActionError { - index: Some(0), - kind: ActionErrorKind::AccountDoesNotExist { account_id: eth_implicit_account }, - }), - ); - assert_eq!(wallet_contract_call_result, &expected_error); +struct NearSigner<'a> { + account_id: &'a AccountIdRef, + signer: InMemorySigner, +} + +fn abi_encode(target: String, action: Action) -> Vec { + const ADD_KEY_SELECTOR: &[u8] = &[0x75, 0x3c, 0xe5, 0xab]; + const TRANSFER_SELECTOR: &[u8] = &[0x3e, 0xd6, 0x41, 0x24]; + + let mut buf = Vec::new(); + match action { + Action::AddKey(add_key) => { + buf.extend_from_slice(ADD_KEY_SELECTOR); + let (public_key_kind, public_key) = match add_key.public_key { + PublicKey::ED25519(key) => (0, key.as_ref().to_vec()), + PublicKey::SECP256K1(key) => (1, key.as_ref().to_vec()), + }; + let nonce = add_key.access_key.nonce; + let (is_full_access, is_limited_allowance, allowance, receiver_id, method_names) = + match add_key.access_key.permission { + AccessKeyPermission::FullAccess => (true, false, 0, String::new(), Vec::new()), + AccessKeyPermission::FunctionCall(permission) => ( + false, + permission.allowance.is_some(), + permission.allowance.unwrap_or_default(), + permission.receiver_id, + permission.method_names, + ), + }; + let tokens = &[ + ethabi::Token::Uint(public_key_kind.into()), + ethabi::Token::Bytes(public_key), + ethabi::Token::Uint(nonce.into()), + ethabi::Token::Bool(is_full_access), + ethabi::Token::Bool(is_limited_allowance), + ethabi::Token::Uint(allowance.into()), + ethabi::Token::String(receiver_id), + ethabi::Token::Array(method_names.into_iter().map(ethabi::Token::String).collect()), + ]; + buf.extend_from_slice(ðabi::encode(tokens)); + } + Action::Transfer(tx) => { + buf.extend_from_slice(TRANSFER_SELECTOR); + let tokens = &[ethabi::Token::String(target), ethabi::Token::Uint(tx.deposit.into())]; + buf.extend_from_slice(ðabi::encode(tokens)); + } + _ => unimplemented!(), } + buf } -/// Wallet Contract function call is rejected because the ETH-implicit account does not exist. -#[test] -fn meta_tx_call_wallet_contract_account_does_not_exist() { - meta_tx_call_wallet_contract(false, true); +fn sign_eth_transaction(transaction: Transaction2930, sk: &SecretKey) -> EthTransactionKind { + let mut rlp_stream = rlp::RlpStream::new(); + rlp_stream.append(&aurora_engine_transactions::eip_2930::TYPE_BYTE); + transaction.rlp_append_unsigned(&mut rlp_stream); + let message_hash = keccak256(rlp_stream.as_raw()); + let signature = sk.sign(&message_hash); + let bytes: [u8; 65] = match signature { + near_crypto::Signature::SECP256K1(x) => x.into(), + _ => panic!("Expected SECP256K1 key"), + }; + let v = bytes[64]; + let r = U256::from_big_endian(&bytes[0..32]); + let s = U256::from_big_endian(&bytes[32..64]); + let signed_transaction = aurora_engine_transactions::eip_2930::SignedTransaction2930 { + transaction, + parity: v, + r, + s, + }; + EthTransactionKind::Eip2930(signed_transaction) } -/// Wallet Contract function call fails because the provided public key does not match the ETH-implicit address. -#[test] -fn meta_tx_call_wallet_contract_unauthorized() { - meta_tx_call_wallet_contract(true, false); +fn keccak256(bytes: &[u8]) -> [u8; 32] { + use sha3::{Digest, Keccak256}; + + Keccak256::digest(bytes).into() } -/// Wallet Contract function call is executed successfully. -#[test] -fn meta_tx_call_wallet_contract_authorized() { - meta_tx_call_wallet_contract(true, true); +fn derive_address(account_id: &AccountIdRef) -> Address { + let bytes = if account_id.as_str().starts_with("0x") { + let buf = hex::decode(&account_id.as_str()[2..42]).expect("account_id is hex encoded"); + return Address::try_from_slice(&buf).expect("slice is correct size"); + } else { + account_id.as_bytes() + }; + let hash = keccak256(bytes); + Address::try_from_slice(&hash[12..32]).expect("slice is correct size") } From 54992b11cf786c682cce4677e8e2d69ac1092784 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Wed, 3 Apr 2024 16:41:25 +0200 Subject: [PATCH 03/10] cargo fmt --- .../address-registrar/src/lib.rs | 4 +- .../wallet-contract/src/eth_emulation.rs | 6 +- .../wallet-contract/src/ethabi_utils.rs | 6 +- .../wallet-contract/src/internal.rs | 49 +---- .../implementation/wallet-contract/src/lib.rs | 61 +++--- .../wallet-contract/src/tests/caller_error.rs | 31 +--- .../wallet-contract/src/tests/emulation.rs | 65 ++----- .../wallet-contract/src/tests/relayer.rs | 100 +++------- .../wallet-contract/src/tests/sanity.rs | 46 +---- .../wallet-contract/src/tests/user_error.rs | 173 ++++-------------- .../wallet-contract/src/tests/utils/codec.rs | 37 +--- .../wallet-contract/src/tests/utils/mod.rs | 9 +- .../src/tests/utils/test_context.rs | 40 +--- .../wallet-contract/src/types.rs | 47 +---- 14 files changed, 151 insertions(+), 523 deletions(-) diff --git a/runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs b/runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs index 59fe2631ca1..157914fa652 100644 --- a/runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs +++ b/runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs @@ -24,9 +24,7 @@ pub struct AddressRegistrar { impl AddressRegistrar { #[init] pub fn new() -> Self { - Self { - addresses: LookupMap::new(StorageKey::Addresses), - } + Self { addresses: LookupMap::new(StorageKey::Addresses) } } pub fn register(&mut self, account_id: AccountId) -> Option { diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs index f1c6137a724..4fe6bd2d12c 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs @@ -40,11 +40,7 @@ pub fn try_emulation( ERC20_BALANCE_OF_SELECTOR => { let (address,): (Address,) = ethabi_utils::abi_decode(&ERC20_BALANCE_OF_SIGNATURE, &tx.data[4..])?; - let args = format!( - r#"{{"account_id": "0x{}{}"}}"#, - hex::encode(address), - suffix - ); + let args = format!(r#"{{"account_id": "0x{}{}"}}"#, hex::encode(address), suffix); Ok(Action::FunctionCall { receiver_id: target.to_string(), method_name: "ft_balance_of".into(), diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/ethabi_utils.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/ethabi_utils.rs index 73746a07b0c..acda0f80a2e 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/ethabi_utils.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/ethabi_utils.rs @@ -44,11 +44,7 @@ where { fn try_from_token(tokens: [Token; 3]) -> Result { let (t1, t2, t3) = tokens.into(); - Ok(( - T1::try_from_token(t1)?, - T2::try_from_token(t2)?, - T3::try_from_token(t3)?, - )) + Ok((T1::try_from_token(t1)?, T2::try_from_token(t2)?, T3::try_from_token(t3)?)) } } diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs index 714cfc8e59b..41e30475e10 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs @@ -44,31 +44,21 @@ pub fn parse_rlp_tx_to_action( // If the transaction is valid then increment the nonce to prevent replay *expected_nonce = expected_nonce.saturating_add(1); - let to = tx - .to - .ok_or(Error::User(UserError::EvmDeployDisallowed))? - .raw(); + let to = tx.to.ok_or(Error::User(UserError::EvmDeployDisallowed))?.raw(); let action = if to != context.current_address && extract_address(target).map(|a| a == to).unwrap_or(false) { // If target is another Ethereum implicit account then the action // must be a transfer (because EOAs are not contracts on Ethereum). - Action::Transfer { - receiver_id: target.to_string(), - yocto_near: 0, - } + Action::Transfer { receiver_id: target.to_string(), yocto_near: 0 } } else { parse_tx_data(target, &tx, context)? }; validate_tx_value(&tx, context, &action)?; // Call to `low_u128` here is safe because of the validation done in `validate_tx_value` - let near_action = action.try_into_near_action( - tx.value - .raw() - .low_u128() - .saturating_mul(MAX_YOCTO_NEAR.into()), - )?; + let near_action = action + .try_into_near_action(tx.value.raw().low_u128().saturating_mul(MAX_YOCTO_NEAR.into()))?; Ok((near_action, validation_outcome)) } @@ -98,9 +88,7 @@ pub fn extract_address(current_account_id: &AccountId) -> Result /// Decode a base-64 encoded string into raw bytes. fn decode_b64(input: &str) -> Result, Error> { let engine = base64::engine::general_purpose::STANDARD; - engine - .decode(input) - .map_err(|_| Error::Relayer(RelayerError::InvalidBase64)) + engine.decode(input).map_err(|_| Error::Relayer(RelayerError::InvalidBase64)) } /// Coverts any Near account ID into a 20-byte address by taking the last 20 bytes @@ -142,13 +130,7 @@ fn parse_tx_data( if yocto_near > MAX_YOCTO_NEAR { return Err(Error::User(UserError::ExcessYoctoNear)); } - Ok(Action::FunctionCall { - receiver_id, - method_name, - args, - gas, - yocto_near, - }) + Ok(Action::FunctionCall { receiver_id, method_name, args, gas, yocto_near }) } TRANSFER_SELECTOR => { let (receiver_id, yocto_near): (String, u32) = @@ -159,10 +141,7 @@ fn parse_tx_data( if yocto_near > MAX_YOCTO_NEAR { return Err(Error::User(UserError::ExcessYoctoNear)); } - Ok(Action::Transfer { - receiver_id, - yocto_near, - }) + Ok(Action::Transfer { receiver_id, yocto_near }) } ADD_KEY_SELECTOR => { let ( @@ -189,10 +168,7 @@ fn parse_tx_data( DELETE_KEY_SELECTOR => { let (public_key_kind, public_key) = ethabi_utils::abi_decode(&DELETE_KEY_SIGNATURE, &tx.data[4..])?; - Ok(Action::DeleteKey { - public_key_kind, - public_key, - }) + Ok(Action::DeleteKey { public_key_kind, public_key }) } _ => eth_emulation::try_emulation(target, tx, context), } @@ -218,14 +194,9 @@ fn validate_tx_relayer_data( return Err(Error::Relayer(RelayerError::InvalidChainId)); } - let to = tx - .to - .ok_or(Error::User(UserError::EvmDeployDisallowed))? - .raw(); + let to = tx.to.ok_or(Error::User(UserError::EvmDeployDisallowed))?.raw(); let target_as_address = extract_address(target).ok(); - let to_equals_target = target_as_address - .map(|target| to == target) - .unwrap_or(false); + let to_equals_target = target_as_address.map(|target| to == target).unwrap_or(false); // Only valid targets satisfy `to == target` or `to == hash(target)` if !to_equals_target && to != hash_to_address(target) { diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs index c7a86009c9c..c2cf3657871 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs @@ -122,11 +122,7 @@ impl WalletContract { PromiseResult::Successful(value) => success_value = Some(value), } } - ExecuteResponse { - success: true, - success_value, - error: None, - } + ExecuteResponse { success: true, success_value, error: None } } #[private] @@ -172,9 +168,7 @@ fn inner_rlp_execute( ext_registrar::ext(account_id).with_static_gas(Gas::from_tgas(5)) }; let address = format!("0x{}", hex::encode(address)); - address_registrar - .lookup(address) - .then(ext.address_check_callback(target, action)) + address_registrar.lookup(address).then(ext.address_check_callback(target, action)) } }; Ok(promise) @@ -193,16 +187,13 @@ fn action_to_promise(target: AccountId, action: near_action::Action) -> Result

match action.access_key.permission { - near_action::AccessKeyPermission::FullAccess => Err(Error::User( - UserError::UnsupportedAction(UnsupportedAction::AddFullAccessKey), - )), + near_action::AccessKeyPermission::FullAccess => { + Err(Error::User(UserError::UnsupportedAction(UnsupportedAction::AddFullAccessKey))) + } near_action::AccessKeyPermission::FunctionCall(access) => Ok(Promise::new(target) .add_access_key_allowance_with_nonce( action.public_key, - access - .allowance - .and_then(Allowance::limited) - .unwrap_or(Allowance::Unlimited), + access.allowance.and_then(Allowance::limited).unwrap_or(Allowance::Unlimited), access.receiver_id, access.method_names.join(","), action.access_key.nonce, @@ -211,32 +202,30 @@ fn action_to_promise(target: AccountId, action: near_action::Action) -> Result

{ Ok(Promise::new(target).delete_key(action.public_key)) } - near_action::Action::CreateAccount(_) => Err(Error::User(UserError::UnsupportedAction( - UnsupportedAction::CreateAccount, - ))), - near_action::Action::DeployContract(_) => Err(Error::User(UserError::UnsupportedAction( - UnsupportedAction::DeployContract, - ))), - near_action::Action::DeleteAccount(_) => Err(Error::User(UserError::UnsupportedAction( - UnsupportedAction::DeleteAccount, - ))), - near_action::Action::Delegate(_) => Err(Error::User(UserError::UnsupportedAction( - UnsupportedAction::Delegate, - ))), + near_action::Action::CreateAccount(_) => { + Err(Error::User(UserError::UnsupportedAction(UnsupportedAction::CreateAccount))) + } + near_action::Action::DeployContract(_) => { + Err(Error::User(UserError::UnsupportedAction(UnsupportedAction::DeployContract))) + } + near_action::Action::DeleteAccount(_) => { + Err(Error::User(UserError::UnsupportedAction(UnsupportedAction::DeleteAccount))) + } + near_action::Action::Delegate(_) => { + Err(Error::User(UserError::UnsupportedAction(UnsupportedAction::Delegate))) + } } } fn create_ban_relayer_promise(current_account_id: AccountId) -> Promise { let pk = env::signer_account_pk(); - Promise::new(current_account_id) - .delete_key(pk) - .function_call_weight( - "ban_relayer".into(), - Vec::new(), - NearToken::from_yoctonear(0), - Gas::from_tgas(1), - GasWeight(1), - ) + Promise::new(current_account_id).delete_key(pk).function_call_weight( + "ban_relayer".into(), + Vec::new(), + NearToken::from_yoctonear(0), + Gas::from_tgas(1), + GasWeight(1), + ) } #[near_sdk::ext_contract(ext_registrar)] diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/caller_error.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/caller_error.rs index 13b98504c33..333ff1db6d2 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/caller_error.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/caller_error.rs @@ -20,12 +20,7 @@ use near_workspaces::types::NearToken; // cost of that transaction (including any attached $NEAR). #[tokio::test] async fn test_insufficient_value() -> anyhow::Result<()> { - let TestContext { - worker, - wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { worker, wallet_contract, wallet_sk, .. } = TestContext::new().await?; let external_account = worker.dev_create_account().await?; @@ -58,10 +53,7 @@ async fn test_insufficient_value() -> anyhow::Result<()> { // Try again with a transaction that has some attached Wei let transfer_amount = NearToken::from_near(1).as_yoctonear(); - let action = Action::Transfer { - receiver_id: account_id.into(), - yocto_near: 0, - }; + let action = Action::Transfer { receiver_id: account_id.into(), yocto_near: 0 }; let signed_transaction = utils::create_signed_transaction( 1, &account_id.parse().unwrap(), @@ -81,16 +73,8 @@ async fn test_insufficient_value() -> anyhow::Result<()> { // It works if we attach the right amount of Near and does not // spend any tokens from the Wallet Contract. - let initial_wallet_balance = wallet_contract - .inner - .as_account() - .view_account() - .await? - .balance; - let action = Action::Transfer { - receiver_id: external_account.id().to_string(), - yocto_near: 0, - }; + let initial_wallet_balance = wallet_contract.inner.as_account().view_account().await?.balance; + let action = Action::Transfer { receiver_id: external_account.id().to_string(), yocto_near: 0 }; let signed_transaction = utils::create_signed_transaction( 2, external_account.id(), @@ -113,12 +97,7 @@ async fn test_insufficient_value() -> anyhow::Result<()> { assert!(result.success); - let final_wallet_balance = wallet_contract - .inner - .as_account() - .view_account() - .await? - .balance; + let final_wallet_balance = wallet_contract.inner.as_account().view_account().await?.balance; assert!(final_wallet_balance >= initial_wallet_balance); diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs index 7b70266ce6b..9acbb7b30be 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs @@ -12,29 +12,14 @@ use near_workspaces::types::NearToken; async fn test_base_token_transfer() -> anyhow::Result<()> { const TRANSFER_AMOUNT: NearToken = NearToken::from_near(2); - let TestContext { - worker, - wallet_contract, - wallet_sk, - wallet_contract_bytes, - .. - } = TestContext::new().await?; + let TestContext { worker, wallet_contract, wallet_sk, wallet_contract_bytes, .. } = + TestContext::new().await?; let (other_wallet, other_address) = TestContext::deploy_wallet(&worker, &wallet_contract_bytes).await?; - let initial_wallet_balance = wallet_contract - .inner - .as_account() - .view_account() - .await? - .balance; - let initial_other_balance = other_wallet - .inner - .as_account() - .view_account() - .await? - .balance; + let initial_wallet_balance = wallet_contract.inner.as_account().view_account().await?.balance; + let initial_other_balance = other_wallet.inner.as_account().view_account().await?.balance; let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { nonce: 0.into(), @@ -48,24 +33,13 @@ async fn test_base_token_transfer() -> anyhow::Result<()> { }; let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); - let result = wallet_contract - .rlp_execute(other_wallet.inner.id().as_str(), &signed_transaction) - .await?; + let result = + wallet_contract.rlp_execute(other_wallet.inner.id().as_str(), &signed_transaction).await?; assert!(result.success); - let final_wallet_balance = wallet_contract - .inner - .as_account() - .view_account() - .await? - .balance; - let final_other_balance = other_wallet - .inner - .as_account() - .view_account() - .await? - .balance; + let final_wallet_balance = wallet_contract.inner.as_account().view_account().await?.balance; + let final_other_balance = other_wallet.inner.as_account().view_account().await?.balance; // Receiver balance increases assert_eq!( @@ -100,9 +74,7 @@ async fn test_erc20_emulation() -> anyhow::Result<()> { } = TestContext::new().await?; let token_contract = nep141::Nep141::deploy(&worker).await?; - token_contract - .mint(wallet_contract.inner.id(), MINT_AMOUNT.as_yoctonear()) - .await?; + token_contract.mint(wallet_contract.inner.id(), MINT_AMOUNT.as_yoctonear()).await?; // Check balance let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { @@ -128,19 +100,12 @@ async fn test_erc20_emulation() -> anyhow::Result<()> { .await?; let balance: U128 = serde_json::from_slice(result.success_value.as_ref().unwrap())?; - assert_eq!( - balance.0, - token_contract - .ft_balance_of(wallet_contract.inner.id()) - .await? - ); + assert_eq!(balance.0, token_contract.ft_balance_of(wallet_contract.inner.id()).await?); // Do a transfer to another account let (other_wallet, other_address) = TestContext::deploy_wallet(&worker, &wallet_contract_bytes).await?; - token_contract - .mint(other_wallet.inner.id(), MINT_AMOUNT.as_yoctonear()) - .await?; + token_contract.mint(other_wallet.inner.id(), MINT_AMOUNT.as_yoctonear()).await?; let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { nonce: 1.into(), gas_price: 0.into(), @@ -169,15 +134,11 @@ async fn test_erc20_emulation() -> anyhow::Result<()> { assert!(result.success); assert_eq!( MINT_AMOUNT.as_yoctonear() - TRANSFER_AMOUNT.as_yoctonear(), - token_contract - .ft_balance_of(wallet_contract.inner.id()) - .await? + token_contract.ft_balance_of(wallet_contract.inner.id()).await? ); assert_eq!( MINT_AMOUNT.as_yoctonear() + TRANSFER_AMOUNT.as_yoctonear(), - token_contract - .ft_balance_of(other_wallet.inner.id()) - .await? + token_contract.ft_balance_of(other_wallet.inner.id()).await? ); Ok(()) diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs index 6256769fb55..15354155746 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs @@ -22,26 +22,14 @@ use near_workspaces::{ // behalf while the user covers the gas costs. #[tokio::test] async fn test_register_relayer() -> anyhow::Result<()> { - let TestContext { - worker, - mut wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { worker, mut wallet_contract, wallet_sk, .. } = TestContext::new().await?; let relayer_pk = wallet_contract.register_relayer(&worker).await?; - let key = wallet_contract - .inner - .as_account() - .view_access_key(&relayer_pk) - .await?; + let key = wallet_contract.inner.as_account().view_access_key(&relayer_pk).await?; match &key.permission { AccessKeyPermission::FunctionCall(access) => { assert_eq!(access.allowance, None); - assert_eq!( - access.receiver_id.as_str(), - wallet_contract.inner.id().as_str() - ); + assert_eq!(access.receiver_id.as_str(), wallet_contract.inner.id().as_str()); assert_eq!(&access.method_names, &[RLP_EXECUTE]); } _ => panic!("Unexpected full access key"), @@ -64,11 +52,7 @@ async fn test_register_relayer() -> anyhow::Result<()> { // If the relayer sends garbage data to the Wallet Contract then it is banned. #[tokio::test] async fn test_relayer_invalid_tx_data() -> anyhow::Result<()> { - let TestContext { - worker, - mut wallet_contract, - .. - } = TestContext::new().await?; + let TestContext { worker, mut wallet_contract, .. } = TestContext::new().await?; async fn new_relayer( worker: &Worker, @@ -119,10 +103,7 @@ async fn test_relayer_invalid_tx_data() -> anyhow::Result<()> { }; for (input, sk) in inputs.into_iter().zip(relayer_keys) { - wallet_contract - .inner - .as_account_mut() - .set_secret_key(sk.clone()); + wallet_contract.inner.as_account_mut().set_secret_key(sk.clone()); rlp_execute(&sk, &wallet_contract, input).await?; } @@ -132,24 +113,14 @@ async fn test_relayer_invalid_tx_data() -> anyhow::Result<()> { // Tests case where relayer sends a transaction signed by the wrong account. #[tokio::test] async fn test_relayer_invalid_sender() -> anyhow::Result<()> { - let TestContext { - worker, - mut wallet_contract, - wallet_contract_bytes, - .. - } = TestContext::new().await?; + let TestContext { worker, mut wallet_contract, wallet_contract_bytes, .. } = + TestContext::new().await?; - let wrong_wallet_sk = TestContext::deploy_wallet(&worker, &wallet_contract_bytes) - .await? - .0 - .sk; + let wrong_wallet_sk = TestContext::deploy_wallet(&worker, &wallet_contract_bytes).await?.0.sk; let relayer_pk = wallet_contract.register_relayer(&worker).await?; let target = "aurora"; - let action = Action::Transfer { - receiver_id: target.into(), - yocto_near: 0, - }; + let action = Action::Transfer { receiver_id: target.into(), yocto_near: 0 }; // Transaction signed by wrong secret key let signed_transaction = utils::create_signed_transaction( 0, @@ -159,9 +130,7 @@ async fn test_relayer_invalid_sender() -> anyhow::Result<()> { &wrong_wallet_sk, ); - let result = wallet_contract - .rlp_execute(target, &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute(target, &signed_transaction).await?; assert!(!result.success); assert_eq!(result.error.as_deref(), Some("Error: faulty relayer")); @@ -175,20 +144,12 @@ async fn test_relayer_invalid_sender() -> anyhow::Result<()> { // hash to the `to` field of the user's signed Ethereum transaction. #[tokio::test] async fn test_relayer_invalid_target() -> anyhow::Result<()> { - let TestContext { - worker, - mut wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { worker, mut wallet_contract, wallet_sk, .. } = TestContext::new().await?; let relayer_pk = wallet_contract.register_relayer(&worker).await?; let real_target = "aurora"; - let action = Action::Transfer { - receiver_id: real_target.into(), - yocto_near: 0, - }; + let action = Action::Transfer { receiver_id: real_target.into(), yocto_near: 0 }; let signed_transaction = utils::create_signed_transaction( 0, &real_target.parse().unwrap(), @@ -197,9 +158,8 @@ async fn test_relayer_invalid_target() -> anyhow::Result<()> { &wallet_sk, ); - let result = wallet_contract - .rlp_execute(&format!("other.{real_target}"), &signed_transaction) - .await?; + let result = + wallet_contract.rlp_execute(&format!("other.{real_target}"), &signed_transaction).await?; assert!(!result.success); assert_eq!(result.error.as_deref(), Some("Error: faulty relayer")); @@ -235,15 +195,10 @@ async fn test_relayer_invalid_address_target() -> anyhow::Result<()> { .transact() .await? .json()?; - let token_address: [u8; 20] = hex::decode( - register_output - .as_ref() - .unwrap() - .strip_prefix("0x") - .unwrap(), - )? - .try_into() - .unwrap(); + let token_address: [u8; 20] = + hex::decode(register_output.as_ref().unwrap().strip_prefix("0x").unwrap())? + .try_into() + .unwrap(); assert_eq!( token_address, hash_to_address(&token_contract.contract.id().as_str().parse().unwrap(),).0 @@ -270,9 +225,8 @@ async fn test_relayer_invalid_address_target() -> anyhow::Result<()> { let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); // Relayer fails to set `target` correctly - let result = wallet_contract - .rlp_execute(register_output.unwrap().as_str(), &signed_transaction) - .await?; + let result = + wallet_contract.rlp_execute(register_output.unwrap().as_str(), &signed_transaction).await?; assert!(!result.success); assert_eq!(result.error.as_deref(), Some("Error: faulty relayer")); @@ -285,13 +239,8 @@ async fn test_relayer_invalid_address_target() -> anyhow::Result<()> { // A relayer sending a transaction signed with the wrong chain id is a ban-worthy offense. #[tokio::test] async fn test_relayer_wrong_chain_id() -> anyhow::Result<()> { - let TestContext { - worker, - mut wallet_contract, - wallet_sk, - wallet_address, - .. - } = TestContext::new().await?; + let TestContext { worker, mut wallet_contract, wallet_sk, wallet_address, .. } = + TestContext::new().await?; let relayer_pk = wallet_contract.register_relayer(&worker).await?; @@ -327,10 +276,7 @@ async fn assert_revoked_key( wallet_contract: &Contract, relayer_pk: &near_workspaces::types::PublicKey, ) { - let key_query = wallet_contract - .as_account() - .view_access_key(relayer_pk) - .await; + let key_query = wallet_contract.as_account().view_access_key(relayer_pk).await; let error_message = format!("{:?}", key_query.unwrap_err()); assert!(error_message.contains("UnknownAccessKey")); diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/sanity.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/sanity.rs index c77f118a45c..37b42ab49f0 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/sanity.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/sanity.rs @@ -10,9 +10,7 @@ use crate::{ // The initial nonce value for a Wallet Contract should be 0. #[tokio::test] async fn test_initial_nonce() -> anyhow::Result<()> { - let TestContext { - wallet_contract, .. - } = TestContext::new().await?; + let TestContext { wallet_contract, .. } = TestContext::new().await?; let nonce = wallet_contract.get_nonce().await?; assert_eq!(nonce, 0); @@ -23,12 +21,7 @@ async fn test_initial_nonce() -> anyhow::Result<()> { // The Wallet Contract should be able to call other Near smart contracts #[tokio::test] async fn test_function_call_action_success() -> anyhow::Result<()> { - let TestContext { - worker, - wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { worker, wallet_contract, wallet_sk, .. } = TestContext::new().await?; utils::deploy_and_call_hello(&worker, &wallet_contract, &wallet_sk, 0).await?; @@ -42,46 +35,27 @@ async fn test_function_call_action_success() -> anyhow::Result<()> { // The Wallet Contract should be able to send $NEAR to other Near accounts. #[tokio::test] async fn test_base_token_transfer_success() -> anyhow::Result<()> { - let TestContext { - worker, - wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { worker, wallet_contract, wallet_sk, .. } = TestContext::new().await?; let transfer_amount = NearToken::from_near(2).as_yoctonear() + 1; let receiver_account = worker.root_account().unwrap(); - let initial_wallet_balance = wallet_contract - .inner - .as_account() - .view_account() - .await - .unwrap() - .balance; + let initial_wallet_balance = + wallet_contract.inner.as_account().view_account().await.unwrap().balance; let initial_receiver_balance = receiver_account.view_account().await.unwrap().balance; let receiver_id = receiver_account.id().as_str().into(); - let action = Action::Transfer { - receiver_id, - yocto_near: 1, - }; + let action = Action::Transfer { receiver_id, yocto_near: 1 }; let value = Wei::new_u128(transfer_amount / (MAX_YOCTO_NEAR as u128)); let signed_transaction = utils::create_signed_transaction(0, receiver_account.id(), value, action, &wallet_sk); - let result = wallet_contract - .rlp_execute(receiver_account.id().as_str(), &signed_transaction) - .await?; + let result = + wallet_contract.rlp_execute(receiver_account.id().as_str(), &signed_transaction).await?; assert!(result.success); - let final_wallet_balance = wallet_contract - .inner - .as_account() - .view_account() - .await - .unwrap() - .balance; + let final_wallet_balance = + wallet_contract.inner.as_account().view_account().await.unwrap().balance; let final_receiver_balance = receiver_account.view_account().await.unwrap().balance; // Check token balances diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs index d7e3563e8b4..d53f607091f 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs @@ -15,11 +15,7 @@ use near_workspaces::types::{KeyType, SecretKey}; // there is no native EVM bytecode interpreter on Near. #[tokio::test] async fn test_evm_deploy() -> anyhow::Result<()> { - let TestContext { - wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { wallet_contract, wallet_sk, .. } = TestContext::new().await?; let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { nonce: 0.into(), @@ -33,15 +29,10 @@ async fn test_evm_deploy() -> anyhow::Result<()> { }; let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); - let result = wallet_contract - .rlp_execute("aurora", &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute("aurora", &signed_transaction).await?; assert!(!result.success); - assert_eq!( - result.error, - Some(Error::User(UserError::EvmDeployDisallowed).to_string()) - ); + assert_eq!(result.error, Some(Error::User(UserError::EvmDeployDisallowed).to_string())); Ok(()) } @@ -51,17 +42,10 @@ async fn test_evm_deploy() -> anyhow::Result<()> { // `u128::MAX // 1e6`. #[tokio::test] async fn test_value_too_large() -> anyhow::Result<()> { - let TestContext { - wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { wallet_contract, wallet_sk, .. } = TestContext::new().await?; let account_id = "aurora"; - let action = Action::Transfer { - receiver_id: account_id.into(), - yocto_near: 0, - }; + let action = Action::Transfer { receiver_id: account_id.into(), yocto_near: 0 }; let signed_transaction = utils::create_signed_transaction( 0, &account_id.parse().unwrap(), @@ -70,15 +54,10 @@ async fn test_value_too_large() -> anyhow::Result<()> { &wallet_sk, ); - let result = wallet_contract - .rlp_execute(account_id, &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute(account_id, &signed_transaction).await?; assert!(!result.success); - assert_eq!( - result.error, - Some(Error::User(UserError::ValueTooLarge).to_string()) - ); + assert_eq!(result.error, Some(Error::User(UserError::ValueTooLarge).to_string())); Ok(()) } @@ -86,17 +65,10 @@ async fn test_value_too_large() -> anyhow::Result<()> { // Test case where `AddKey`/`DeleteKey` action contains an unknown public key kind #[tokio::test] async fn test_unknown_public_key_kind() -> anyhow::Result<()> { - let TestContext { - wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { wallet_contract, wallet_sk, .. } = TestContext::new().await?; let account_id = "aurora"; - let action = Action::DeleteKey { - public_key_kind: 2, - public_key: b"a_new_key_type".to_vec(), - }; + let action = Action::DeleteKey { public_key_kind: 2, public_key: b"a_new_key_type".to_vec() }; let signed_transaction = utils::create_signed_transaction( 0, &account_id.parse().unwrap(), @@ -105,15 +77,10 @@ async fn test_unknown_public_key_kind() -> anyhow::Result<()> { &wallet_sk, ); - let result = wallet_contract - .rlp_execute(account_id, &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute(account_id, &signed_transaction).await?; assert!(!result.success); - assert_eq!( - result.error, - Some(Error::User(UserError::UnknownPublicKeyKind).to_string()) - ); + assert_eq!(result.error, Some(Error::User(UserError::UnknownPublicKeyKind).to_string())); let action = Action::AddKey { public_key_kind: 2, @@ -133,15 +100,10 @@ async fn test_unknown_public_key_kind() -> anyhow::Result<()> { &wallet_sk, ); - let result = wallet_contract - .rlp_execute(account_id, &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute(account_id, &signed_transaction).await?; assert!(!result.success); - assert_eq!( - result.error, - Some(Error::User(UserError::UnknownPublicKeyKind).to_string()) - ); + assert_eq!(result.error, Some(Error::User(UserError::UnknownPublicKeyKind).to_string())); Ok(()) } @@ -160,10 +122,7 @@ async fn test_invalid_public_key() -> anyhow::Result<()> { let nonce = wallet_contract.get_nonce().await?; let account_id = "aurora"; - let action = Action::DeleteKey { - public_key_kind, - public_key: public_key.clone(), - }; + let action = Action::DeleteKey { public_key_kind, public_key: public_key.clone() }; let signed_transaction = utils::create_signed_transaction( nonce, &account_id.parse().unwrap(), @@ -172,15 +131,10 @@ async fn test_invalid_public_key() -> anyhow::Result<()> { wallet_sk, ); - let result = wallet_contract - .rlp_execute(account_id, &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute(account_id, &signed_transaction).await?; assert!(!result.success); - assert_eq!( - result.error, - Some(Error::User(expected_error.clone()).to_string()) - ); + assert_eq!(result.error, Some(Error::User(expected_error.clone()).to_string())); let action = Action::AddKey { public_key_kind, @@ -200,9 +154,7 @@ async fn test_invalid_public_key() -> anyhow::Result<()> { wallet_sk, ); - let result = wallet_contract - .rlp_execute(account_id, &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute(account_id, &signed_transaction).await?; assert!(!result.success); assert_eq!(result.error, Some(Error::User(expected_error).to_string())); @@ -213,22 +165,10 @@ async fn test_invalid_public_key() -> anyhow::Result<()> { let ctx = TestContext::new().await?; assert_invalid_pk(&ctx, 0, Vec::new(), UserError::InvalidEd25519Key).await?; - assert_invalid_pk( - &ctx, - 0, - b"wrong_length".to_vec(), - UserError::InvalidEd25519Key, - ) - .await?; + assert_invalid_pk(&ctx, 0, b"wrong_length".to_vec(), UserError::InvalidEd25519Key).await?; assert_invalid_pk(&ctx, 1, Vec::new(), UserError::InvalidSecp256k1Key).await?; - assert_invalid_pk( - &ctx, - 1, - b"wrong_length".to_vec(), - UserError::InvalidSecp256k1Key, - ) - .await?; + assert_invalid_pk(&ctx, 1, b"wrong_length".to_vec(), UserError::InvalidSecp256k1Key).await?; Ok(()) } @@ -236,11 +176,7 @@ async fn test_invalid_public_key() -> anyhow::Result<()> { // Tests case where we try to add an access key with an invalid `receiver_id` #[tokio::test] async fn test_invalid_public_key_account_id() -> anyhow::Result<()> { - let TestContext { - wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { wallet_contract, wallet_sk, .. } = TestContext::new().await?; let key = SecretKey::from_random(KeyType::ED25519); let account_id = "aurora"; @@ -263,15 +199,10 @@ async fn test_invalid_public_key_account_id() -> anyhow::Result<()> { &wallet_sk, ); - let result = wallet_contract - .rlp_execute(account_id, &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute(account_id, &signed_transaction).await?; assert!(!result.success); - assert_eq!( - result.error, - Some(Error::User(UserError::InvalidAccessKeyAccountId).to_string()) - ); + assert_eq!(result.error, Some(Error::User(UserError::InvalidAccessKeyAccountId).to_string())); Ok(()) } @@ -281,11 +212,7 @@ async fn test_invalid_public_key_account_id() -> anyhow::Result<()> { // such as deploying a different contract to an Eth implicit address. #[tokio::test] async fn test_cannot_add_full_access_key() -> anyhow::Result<()> { - let TestContext { - wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { wallet_contract, wallet_sk, .. } = TestContext::new().await?; let key = SecretKey::from_random(KeyType::ED25519); let action = Action::AddKey { @@ -314,10 +241,8 @@ async fn test_cannot_add_full_access_key() -> anyhow::Result<()> { assert_eq!( result.error, Some( - Error::User(UserError::UnsupportedAction( - UnsupportedAction::AddFullAccessKey - )) - .to_string() + Error::User(UserError::UnsupportedAction(UnsupportedAction::AddFullAccessKey)) + .to_string() ) ); @@ -328,11 +253,7 @@ async fn test_cannot_add_full_access_key() -> anyhow::Result<()> { // Action or emulated Ethereum standard. #[tokio::test] async fn test_bad_data() -> anyhow::Result<()> { - let TestContext { - wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { wallet_contract, wallet_sk, .. } = TestContext::new().await?; let account_id = "aurora"; let to = Address::new(hash_to_address(&account_id.parse().unwrap())); @@ -348,15 +269,10 @@ async fn test_bad_data() -> anyhow::Result<()> { }; let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); - let result = wallet_contract - .rlp_execute(account_id, &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute(account_id, &signed_transaction).await?; assert!(!result.success); - assert_eq!( - result.error, - Some(Error::User(UserError::UnknownFunctionSelector).to_string()) - ); + assert_eq!(result.error, Some(Error::User(UserError::UnknownFunctionSelector).to_string())); let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { nonce: 1.into(), @@ -375,15 +291,10 @@ async fn test_bad_data() -> anyhow::Result<()> { }; let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); - let result = wallet_contract - .rlp_execute(account_id, &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute(account_id, &signed_transaction).await?; assert!(!result.success); - assert_eq!( - result.error, - Some(Error::User(UserError::InvalidAbiEncodedData).to_string()) - ); + assert_eq!(result.error, Some(Error::User(UserError::InvalidAbiEncodedData).to_string())); let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { nonce: 2.into(), @@ -397,15 +308,10 @@ async fn test_bad_data() -> anyhow::Result<()> { }; let signed_transaction = crypto::sign_transaction(transaction, &wallet_sk); - let result = wallet_contract - .rlp_execute(account_id, &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute(account_id, &signed_transaction).await?; assert!(!result.success); - assert_eq!( - result.error, - Some(Error::User(UserError::InvalidAbiEncodedData).to_string()) - ); + assert_eq!(result.error, Some(Error::User(UserError::InvalidAbiEncodedData).to_string())); Ok(()) } @@ -413,11 +319,7 @@ async fn test_bad_data() -> anyhow::Result<()> { // Test case where the action contains more than 1_000_000 yocotoNear directly. #[tokio::test] async fn test_excess_yocto() -> anyhow::Result<()> { - let TestContext { - wallet_contract, - wallet_sk, - .. - } = TestContext::new().await?; + let TestContext { wallet_contract, wallet_sk, .. } = TestContext::new().await?; let account_id = "aurora"; let action = Action::Transfer { @@ -432,15 +334,10 @@ async fn test_excess_yocto() -> anyhow::Result<()> { &wallet_sk, ); - let result = wallet_contract - .rlp_execute(account_id, &signed_transaction) - .await?; + let result = wallet_contract.rlp_execute(account_id, &signed_transaction).await?; assert!(!result.success); - assert_eq!( - result.error, - Some(Error::User(UserError::ExcessYoctoNear).to_string()) - ); + assert_eq!(result.error, Some(Error::User(UserError::ExcessYoctoNear).to_string())); Ok(()) } diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/codec.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/codec.rs index 95b5e1d8519..fd56b204da0 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/codec.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/codec.rs @@ -4,13 +4,7 @@ use aurora_engine_transactions::EthTransactionKind; pub fn abi_encode(action: Action) -> Vec { let mut buf = Vec::new(); match action { - Action::FunctionCall { - receiver_id, - method_name, - args, - gas, - yocto_near, - } => { + Action::FunctionCall { receiver_id, method_name, args, gas, yocto_near } => { buf.extend_from_slice(crate::types::FUNCTION_CALL_SELECTOR); let tokens = &[ ethabi::Token::String(receiver_id), @@ -21,15 +15,10 @@ pub fn abi_encode(action: Action) -> Vec { ]; buf.extend_from_slice(ðabi::encode(tokens)); } - Action::Transfer { - receiver_id, - yocto_near, - } => { + Action::Transfer { receiver_id, yocto_near } => { buf.extend_from_slice(crate::types::TRANSFER_SELECTOR); - let tokens = &[ - ethabi::Token::String(receiver_id), - ethabi::Token::Uint(yocto_near.into()), - ]; + let tokens = + &[ethabi::Token::String(receiver_id), ethabi::Token::Uint(yocto_near.into())]; buf.extend_from_slice(ðabi::encode(tokens)); } Action::AddKey { @@ -51,24 +40,14 @@ pub fn abi_encode(action: Action) -> Vec { ethabi::Token::Bool(is_limited_allowance), ethabi::Token::Uint(allowance.into()), ethabi::Token::String(receiver_id), - ethabi::Token::Array( - method_names - .into_iter() - .map(ethabi::Token::String) - .collect(), - ), + ethabi::Token::Array(method_names.into_iter().map(ethabi::Token::String).collect()), ]; buf.extend_from_slice(ðabi::encode(tokens)); } - Action::DeleteKey { - public_key_kind, - public_key, - } => { + Action::DeleteKey { public_key_kind, public_key } => { buf.extend_from_slice(crate::types::DELETE_KEY_SELECTOR); - let tokens = &[ - ethabi::Token::Uint(public_key_kind.into()), - ethabi::Token::Bytes(public_key), - ]; + let tokens = + &[ethabi::Token::Uint(public_key_kind.into()), ethabi::Token::Bytes(public_key)]; buf.extend_from_slice(ðabi::encode(tokens)); } }; diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs index 7432501403a..ac0233a2861 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs @@ -32,9 +32,8 @@ pub async fn deploy_and_call_hello( let signed_transaction = create_signed_transaction(nonce, hello_contract.id(), Wei::zero(), action, wallet_sk); - let result = wallet_contract - .rlp_execute(hello_contract.id().as_str(), &signed_transaction) - .await?; + let result = + wallet_contract.rlp_execute(hello_contract.id().as_str(), &signed_transaction).await?; if result.success_value.as_deref() != Some(br#""Hello, Aurora!""#.as_slice()) { anyhow::bail!("Call to hello contract failed: {:?}", result.error); @@ -54,9 +53,7 @@ pub fn create_signed_transaction( nonce: nonce.into(), gas_price: 0.into(), gas_limit: 0.into(), - to: Some(Address::new(hash_to_address( - &target.as_str().parse().unwrap(), - ))), + to: Some(Address::new(hash_to_address(&target.as_str().parse().unwrap()))), value, data: codec::abi_encode(action), chain_id: CHAIN_ID, diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs index 091799d110e..91b2a972289 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs @@ -118,11 +118,7 @@ impl WalletContract { .into_result()? .json()?; - assert!( - result.success, - "Adding Relayer's key failed: {:?}", - result.error - ); + assert!(result.success, "Adding Relayer's key failed: {:?}", result.error); // Tell near-workspaces to use this new key instead when // signing transactions from the Wallet Contract @@ -151,17 +147,11 @@ impl TestContext { // Restore address registrar account id file let output = Command::new("git") .current_dir(BASE_DIR) - .args([ - OsStr::new("checkout"), - address_registrar_account_id_path(".").as_os_str(), - ]) + .args([OsStr::new("checkout"), address_registrar_account_id_path(".").as_os_str()]) .output() .await?; if !output.status.success() { - anyhow::bail!( - "git checkout failed: {}", - String::from_utf8_lossy(&output.stderr) - ); + anyhow::bail!("git checkout failed: {}", String::from_utf8_lossy(&output.stderr)); } let (wallet_contract, wallet_address) = @@ -179,28 +169,16 @@ impl TestContext { } async fn deploy_address_registrar(worker: &Worker) -> anyhow::Result { - let base_dir = Path::new(BASE_DIR) - .parent() - .unwrap() - .join("address-registrar"); + let base_dir = Path::new(BASE_DIR).parent().unwrap().join("address-registrar"); let contract_bytes = build_contract(base_dir, "eth-address-registrar").await?; let contract = worker.dev_deploy(&contract_bytes).await?; // Initialize the contract - contract - .call("new") - .transact() - .await - .unwrap() - .into_result() - .unwrap(); + contract.call("new").transact().await.unwrap().into_result().unwrap(); // Update the file where the Wallet Contract gets the address registrar account id from - tokio::fs::write( - address_registrar_account_id_path(BASE_DIR), - contract.id().as_bytes(), - ) - .await?; + tokio::fs::write(address_registrar_account_id_path(BASE_DIR), contract.id().as_bytes()) + .await?; Ok(contract) } @@ -261,7 +239,5 @@ async fn build_contract>( } fn address_registrar_account_id_path(base_dir: &str) -> PathBuf { - Path::new(base_dir) - .join("src") - .join("ADDRESS_REGISTRAR_ACCOUNT_ID") + Path::new(base_dir).join("src").join("ADDRESS_REGISTRAR_ACCOUNT_ID") } diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/types.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/types.rs index 619e10577d3..975e1304a25 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/types.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/types.rs @@ -59,11 +59,7 @@ pub struct ExecuteResponse { impl From for ExecuteResponse { fn from(value: Error) -> Self { - Self { - success: false, - success_value: None, - error: Some(format!("{value}")), - } + Self { success: false, success_value: None, error: Some(format!("{value}")) } } } @@ -86,12 +82,7 @@ impl ExecutionContext { attached_deposit: NearToken, ) -> Result { let current_address = crate::internal::extract_address(¤t_account_id)?; - Ok(Self { - current_address, - attached_deposit, - predecessor_account_id, - current_account_id, - }) + Ok(Self { current_address, attached_deposit, predecessor_account_id, current_account_id }) } } @@ -150,13 +141,7 @@ impl Action { additional_value: u128, ) -> Result { let action = match self { - Action::FunctionCall { - receiver_id: _, - method_name, - args, - gas, - yocto_near, - } => { + Action::FunctionCall { receiver_id: _, method_name, args, gas, yocto_near } => { let action = FunctionCallAction { method_name, args, @@ -167,10 +152,7 @@ impl Action { }; near_action::Action::FunctionCall(action) } - Action::Transfer { - receiver_id: _, - yocto_near, - } => { + Action::Transfer { receiver_id: _, yocto_near } => { let action = TransferAction { deposit: NearToken::from_yoctonear( additional_value.saturating_add(yocto_near.into()), @@ -190,16 +172,9 @@ impl Action { } => { let public_key = construct_public_key(public_key_kind, &public_key)?; let access_key = if is_full_access { - AccessKey { - nonce, - permission: AccessKeyPermission::FullAccess, - } + AccessKey { nonce, permission: AccessKeyPermission::FullAccess } } else { - let allowance = if is_limited_allowance { - Some(allowance) - } else { - None - }; + let allowance = if is_limited_allowance { Some(allowance) } else { None }; AccessKey { nonce, permission: AccessKeyPermission::FunctionCall(FunctionCallPermission { @@ -211,16 +186,10 @@ impl Action { }), } }; - let action = AddKeyAction { - public_key, - access_key, - }; + let action = AddKeyAction { public_key, access_key }; near_action::Action::AddKey(action) } - Action::DeleteKey { - public_key_kind, - public_key, - } => { + Action::DeleteKey { public_key_kind, public_key } => { let action = DeleteKeyAction { public_key: construct_public_key(public_key_kind, &public_key)?, }; From 447feefc0a7f6f13aa13d15c85918131dadf02c2 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Wed, 3 Apr 2024 16:46:50 +0200 Subject: [PATCH 04/10] Add doc comments to public contract methods --- .../address-registrar/src/lib.rs | 16 ++++++++++++ .../implementation/wallet-contract/src/lib.rs | 25 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs b/runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs index 157914fa652..c37e6ab8e96 100644 --- a/runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs +++ b/runtime/near-wallet-contract/implementation/address-registrar/src/lib.rs @@ -27,6 +27,12 @@ impl AddressRegistrar { Self { addresses: LookupMap::new(StorageKey::Addresses) } } + /// Computes the address associated with the given `account_id` and + /// attempts to store the mapping `address -> account_id`. If there is + /// a collision where the given `account_id` has the same address as a + /// previously registered one then the mapping is NOT updated and `None` + /// is returned. Otherwise, the mapping is stored and the address is + /// returned as a hex-encoded string with `0x` prefix. pub fn register(&mut self, account_id: AccountId) -> Option { let address = account_id_to_address(&account_id); @@ -50,6 +56,12 @@ impl AddressRegistrar { } } + /// Attempt to look up the account ID associated with the given address. + /// If an entry for that address is found then the associated account id + /// is returned, otherwise `None` is returned. Use the `register` method + /// to add entries to the map. + /// This function will panic if the given address is not the hex-encoding + /// of a 20-byte array. The `0x` prefix is optional. pub fn lookup(&self, address: String) -> Option { let address = { let mut buf = [0u8; 20]; @@ -60,6 +72,10 @@ impl AddressRegistrar { self.addresses.get(&address).cloned() } + /// Computes the address associated with the given `account_id` and + /// returns it as a hex-encoded string with `0x` prefix. This function + /// does not update the mapping stored in this contract. If you want + /// to register an account ID use the `register` method. pub fn get_address(&self, account_id: AccountId) -> String { let address = account_id_to_address(&account_id); format!("0x{}", hex::encode(address)) diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs index c2cf3657871..3f30d3e6847 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs @@ -33,10 +33,35 @@ pub struct WalletContract { #[near_bindgen] impl WalletContract { + /// Return the nonce value currently stored in the contract. + /// Following the Ethereum protocol, only transactions with nonce equal + /// to the current value will be accepted. + /// Additionally, the Ethereum protocol requires the nonce of an account increment + /// by 1 each time a transaction with the correct nonce and a valid signature + /// is submitted (even if that transaction eventually fails). In this way, each + /// nonce value can only be used once (hence the name "nonce") and thus transaction + /// replay is prevented. pub fn get_nonce(&self) -> U64 { U64(self.nonce) } + /// This is the main entry point into this contract. It accepts an RLP-encoded + /// Ethereum transaction signed by the private key associated with the address + /// for the account where this contract is deployed. RLP is a binary format, + /// so the argument is actually passed as a base64-encoded string. + /// The Ethereum transaction represents a Near action the owner of the address + /// wants to perform. This method decodes that action from the Ethereum transaction + /// and crates a promise to perform that action. + /// Actions on Near are sent to a particular account ID where they are supposed to + /// be executed (for example, a `FunctionCall` action is sent to the contract + /// which will execute the method). In the Ethereum transaction only the address + /// of the target can be specified because it does not have a notion of named accounts + /// like Near has. The `target` field of this method gives the actual account ID + /// that the action will be sent to. The `target` must itself be an eth-implicit + /// account and match the `to` address of the Ethereum transaction; or `target` + /// must hash to the address given in the `to` field of the Ethereum transaction. + /// The output of this function is an `ExecuteResponse` which gives the output + /// of the Near action or an error message if there was a problem during the execution. #[payable] pub fn rlp_execute( &mut self, From 9bb90c09357d822db77d86637bf8e2ce61a7dbbc Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Wed, 3 Apr 2024 16:56:31 +0200 Subject: [PATCH 05/10] Remove unused Near actions --- .../implementation/wallet-contract/src/lib.rs | 15 -------- .../wallet-contract/src/near_action.rs | 34 +++---------------- 2 files changed, 4 insertions(+), 45 deletions(-) diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs index 3f30d3e6847..5e81dde5cad 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/lib.rs @@ -208,9 +208,6 @@ fn action_to_promise(target: AccountId, action: near_action::Action) -> Result

Ok(Promise::new(target).transfer(action.deposit)), - near_action::Action::Stake(action) => { - Ok(Promise::new(target).stake(action.stake, action.public_key)) - } near_action::Action::AddKey(action) => match action.access_key.permission { near_action::AccessKeyPermission::FullAccess => { Err(Error::User(UserError::UnsupportedAction(UnsupportedAction::AddFullAccessKey))) @@ -227,18 +224,6 @@ fn action_to_promise(target: AccountId, action: near_action::Action) -> Result

{ Ok(Promise::new(target).delete_key(action.public_key)) } - near_action::Action::CreateAccount(_) => { - Err(Error::User(UserError::UnsupportedAction(UnsupportedAction::CreateAccount))) - } - near_action::Action::DeployContract(_) => { - Err(Error::User(UserError::UnsupportedAction(UnsupportedAction::DeployContract))) - } - near_action::Action::DeleteAccount(_) => { - Err(Error::User(UserError::UnsupportedAction(UnsupportedAction::DeleteAccount))) - } - near_action::Action::Delegate(_) => { - Err(Error::User(UserError::UnsupportedAction(UnsupportedAction::Delegate))) - } } } diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/near_action.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/near_action.rs index e43cb7bb6c7..4b7f9491270 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/near_action.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/near_action.rs @@ -1,30 +1,20 @@ -//! Definition of `Action` for Near protocol. +//! Partial definition of `Action` for Near protocol. //! Unfortunately we cannot use `near-primitives` directly in the contract //! because it uses dependencies that do not compile to Wasm (at least //! not without some extra feature flags that `near-primitives` currently //! does not include). +//! Some variants of `near_primitives::Action` are intentionally left out +//! because they are not possible to do with the wallet contract +//! (e.g. `DeleteAccount`). use near_sdk::{AccountId, Gas, NearToken, PublicKey}; #[derive(Debug, serde::Deserialize, serde::Serialize)] pub enum Action { - CreateAccount(CreateAccountAction), - DeployContract(DeployContractAction), FunctionCall(FunctionCallAction), Transfer(TransferAction), - Stake(StakeAction), AddKey(AddKeyAction), DeleteKey(DeleteKeyAction), - DeleteAccount(DeleteAccountAction), - Delegate(SignedDelegateAction), -} - -#[derive(Debug, serde::Deserialize, serde::Serialize)] -pub struct CreateAccountAction {} - -#[derive(Debug, serde::Deserialize, serde::Serialize)] -pub struct DeployContractAction { - pub code: Vec, } #[derive(Debug, serde::Deserialize, serde::Serialize)] @@ -40,12 +30,6 @@ pub struct TransferAction { pub deposit: NearToken, } -#[derive(Debug, serde::Deserialize, serde::Serialize)] -pub struct StakeAction { - pub stake: NearToken, - pub public_key: PublicKey, -} - #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct AddKeyAction { pub public_key: PublicKey, @@ -75,13 +59,3 @@ pub struct FunctionCallPermission { pub struct DeleteKeyAction { pub public_key: PublicKey, } - -#[derive(Debug, serde::Deserialize, serde::Serialize)] -pub struct DeleteAccountAction { - pub beneficiary_id: AccountId, -} - -/// This is just a placeholder for now since Delegate actions will -/// not be supported by the Wallet Contract in V1. -#[derive(Debug, serde::Deserialize, serde::Serialize)] -pub struct SignedDelegateAction; From 7ed4741cc369655fe33dd7ae540202609cffd065 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Wed, 3 Apr 2024 17:04:33 +0200 Subject: [PATCH 06/10] Rename hash_to_address -> account_id_to_address; add test --- .../implementation/wallet-contract/src/internal.rs | 12 ++++++++++-- .../wallet-contract/src/tests/emulation.rs | 6 +++--- .../wallet-contract/src/tests/relayer.rs | 4 ++-- .../wallet-contract/src/tests/user_error.rs | 4 ++-- .../wallet-contract/src/tests/utils/mod.rs | 4 ++-- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs index 41e30475e10..03d86f4f7ca 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs @@ -93,7 +93,7 @@ fn decode_b64(input: &str) -> Result, Error> { /// Coverts any Near account ID into a 20-byte address by taking the last 20 bytes /// of the keccak256 hash. -pub fn hash_to_address(account_id: &AccountId) -> Address { +pub fn account_id_to_address(account_id: &AccountId) -> Address { let hash = keccak256(account_id.as_bytes()); let mut result = [0u8; 20]; result.copy_from_slice(&hash[12..32]); @@ -199,7 +199,7 @@ fn validate_tx_relayer_data( let to_equals_target = target_as_address.map(|target| to == target).unwrap_or(false); // Only valid targets satisfy `to == target` or `to == hash(target)` - if !to_equals_target && to != hash_to_address(target) { + if !to_equals_target && to != account_id_to_address(target) { return Err(Error::Relayer(RelayerError::InvalidTarget)); } @@ -255,3 +255,11 @@ fn validate_tx_value( fn test_value_max() { assert_eq!(VALUE_MAX, U256::from(u128::MAX / 1_000_000)); } + +#[test] +fn test_account_id_to_address() { + let account_id: AccountId = "aurora".parse().unwrap(); + let address = + Address::from_slice(&hex::decode("4444588443c3a91288c5002483449aba1054192b").unwrap()); + assert_eq!(account_id_to_address(&account_id), address); +} diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs index 9acbb7b30be..4837564b252 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/emulation.rs @@ -1,5 +1,5 @@ use crate::{ - internal::{hash_to_address, CHAIN_ID, MAX_YOCTO_NEAR}, + internal::{account_id_to_address, CHAIN_ID, MAX_YOCTO_NEAR}, tests::utils::{crypto, nep141, test_context::TestContext}, }; use aurora_engine_types::types::{Address, Wei}; @@ -81,7 +81,7 @@ async fn test_erc20_emulation() -> anyhow::Result<()> { nonce: 0.into(), gas_price: 0.into(), gas_limit: 0.into(), - to: Some(Address::new(hash_to_address( + to: Some(Address::new(account_id_to_address( &token_contract.contract.id().as_str().parse().unwrap(), ))), value: Wei::zero(), @@ -110,7 +110,7 @@ async fn test_erc20_emulation() -> anyhow::Result<()> { nonce: 1.into(), gas_price: 0.into(), gas_limit: 0.into(), - to: Some(Address::new(hash_to_address( + to: Some(Address::new(account_id_to_address( &token_contract.contract.id().as_str().parse().unwrap(), ))), value: Wei::zero(), diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs index 15354155746..10b17adaa7c 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/relayer.rs @@ -1,5 +1,5 @@ use crate::{ - internal::{hash_to_address, CHAIN_ID}, + internal::{account_id_to_address, CHAIN_ID}, tests::{ utils::{ self, codec, crypto, nep141, @@ -201,7 +201,7 @@ async fn test_relayer_invalid_address_target() -> anyhow::Result<()> { .unwrap(); assert_eq!( token_address, - hash_to_address(&token_contract.contract.id().as_str().parse().unwrap(),).0 + account_id_to_address(&token_contract.contract.id().as_str().parse().unwrap(),).0 ); // Set up a relayer with control to send transactions via the Wallet Contract account. diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs index d53f607091f..a0a1f918fcd 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs @@ -4,7 +4,7 @@ use crate::{ error::{Error, UnsupportedAction, UserError}, - internal::{hash_to_address, CHAIN_ID}, + internal::{account_id_to_address, CHAIN_ID}, tests::utils::{self, crypto, test_context::TestContext}, types::{Action, FUNCTION_CALL_SELECTOR}, }; @@ -256,7 +256,7 @@ async fn test_bad_data() -> anyhow::Result<()> { let TestContext { wallet_contract, wallet_sk, .. } = TestContext::new().await?; let account_id = "aurora"; - let to = Address::new(hash_to_address(&account_id.parse().unwrap())); + let to = Address::new(account_id_to_address(&account_id.parse().unwrap())); let transaction = aurora_engine_transactions::eip_2930::Transaction2930 { nonce: 0.into(), gas_price: 0.into(), diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs index ac0233a2861..d142a7235bf 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/mod.rs @@ -1,5 +1,5 @@ use crate::{ - internal::{hash_to_address, CHAIN_ID}, + internal::{account_id_to_address, CHAIN_ID}, tests::utils::test_context::WalletContract, types::Action, }; @@ -53,7 +53,7 @@ pub fn create_signed_transaction( nonce: nonce.into(), gas_price: 0.into(), gas_limit: 0.into(), - to: Some(Address::new(hash_to_address(&target.as_str().parse().unwrap()))), + to: Some(Address::new(account_id_to_address(&target.as_str().parse().unwrap()))), value, data: codec::abi_encode(action), chain_id: CHAIN_ID, From ee16f2bf75aabea09ecad4ccf1a44d6950ffd26b Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Wed, 3 Apr 2024 19:44:02 +0200 Subject: [PATCH 07/10] Add comment about account suffix --- .../wallet-contract/src/eth_emulation.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs index 4fe6bd2d12c..4174e92acc3 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/eth_emulation.rs @@ -30,6 +30,12 @@ pub fn try_emulation( if tx.data.len() < 4 { return Err(Error::User(UserError::InvalidAbiEncodedData)); } + // In production eth-implicit accounts are top-level, so this suffix will + // always be empty. The purpose of finding a suffix is that it allows for + // testing environments where the wallet contract is deployed to an address + // that is a sub-account. For example, this allows testing on Near testnet + // before the eth-implicit accounts feature is stabilized. + // The suffix is only needed in testing. let suffix = context .current_account_id .as_str() @@ -40,6 +46,11 @@ pub fn try_emulation( ERC20_BALANCE_OF_SELECTOR => { let (address,): (Address,) = ethabi_utils::abi_decode(&ERC20_BALANCE_OF_SIGNATURE, &tx.data[4..])?; + // The account ID is assumed to have the same suffix as the current account because + // (1) in production this is correct as all eth-implicit accounts are top-level and + // (2) in testing environments where the addresses are sub-accounts, they are still + // assumed to all be deployed to the same namespace so that they will all have the + // same suffix. let args = format!(r#"{{"account_id": "0x{}{}"}}"#, hex::encode(address), suffix); Ok(Action::FunctionCall { receiver_id: target.to_string(), From fc96b2e8f6584421a338f62d889553320cfe505f Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Wed, 3 Apr 2024 20:21:19 +0200 Subject: [PATCH 08/10] Update TODO comments --- .../implementation/wallet-contract/src/internal.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs index 03d86f4f7ca..ebcccc11047 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/internal.rs @@ -12,7 +12,7 @@ use base64::Engine; use ethabi::{ethereum_types::U256, Address}; use near_sdk::{AccountId, NearToken}; -// TODO: Decide on chain id. +// TODO(eth-implicit): Decide on chain id. pub const CHAIN_ID: u64 = 0x4ea7; const U64_MAX: U256 = U256([u64::MAX, 0, 0, 0]); /// Only up to this amount of yoctoNear can be directly mentioned in an action, @@ -69,7 +69,11 @@ pub fn parse_rlp_tx_to_action( pub fn extract_address(current_account_id: &AccountId) -> Result { let hex_str = current_account_id.as_bytes(); - // TODO: in production be strict about account ID is exactly 42 bytes. + // The length must be at least 42 characters because it begins with + // `0x` and then a 20-byte hex-encoded string. In production it will + // be exactly 42 characters because eth-implicit accounts will always + // be top-level, but for testing we may have them be sub-accounts. + // In this case then the length will be longer than 42 characters. if hex_str.len() < 42 { return Err(Error::AccountId(AccountIdError::AccountIdTooShort)); } From b900f78f03b35c7aa330871fe671090a30353b4c Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Thu, 4 Apr 2024 17:48:01 +0200 Subject: [PATCH 09/10] Remove usage of git in tests --- .../src/tests/utils/test_context.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs index 91b2a972289..b20ac6eaa7b 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/utils/test_context.rs @@ -14,10 +14,7 @@ use near_workspaces::{ types::{KeyType, NearToken, PublicKey, SecretKey}, Account, Contract, Worker, }; -use std::{ - ffi::OsStr, - path::{Path, PathBuf}, -}; +use std::path::{Path, PathBuf}; use tokio::{process::Command, sync::Mutex}; const BASE_DIR: &str = std::env!("CARGO_MANIFEST_DIR"); @@ -142,17 +139,12 @@ impl TestContext { let _guard = LOCK.lock().await; let worker = near_workspaces::sandbox().await?; + let registrar_id_path = address_registrar_account_id_path(BASE_DIR); + let original_registrar_id = tokio::fs::read(®istrar_id_path).await?; let address_registrar = Self::deploy_address_registrar(&worker).await?; let wallet_contract_bytes = build_contract(BASE_DIR, PACKAGE_NAME).await?; // Restore address registrar account id file - let output = Command::new("git") - .current_dir(BASE_DIR) - .args([OsStr::new("checkout"), address_registrar_account_id_path(".").as_os_str()]) - .output() - .await?; - if !output.status.success() { - anyhow::bail!("git checkout failed: {}", String::from_utf8_lossy(&output.stderr)); - } + tokio::fs::write(registrar_id_path, &original_registrar_id).await?; let (wallet_contract, wallet_address) = Self::deploy_wallet(&worker, &wallet_contract_bytes).await?; From 24bd5747e318e1fbfed6664410bef34c46afe150 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Thu, 4 Apr 2024 17:48:51 +0200 Subject: [PATCH 10/10] Fix typo --- .../implementation/wallet-contract/src/tests/user_error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs index a0a1f918fcd..b9a11fd93be 100644 --- a/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs +++ b/runtime/near-wallet-contract/implementation/wallet-contract/src/tests/user_error.rs @@ -316,7 +316,7 @@ async fn test_bad_data() -> anyhow::Result<()> { Ok(()) } -// Test case where the action contains more than 1_000_000 yocotoNear directly. +// Test case where the action contains more than 1_000_000 yoctoNear directly. #[tokio::test] async fn test_excess_yocto() -> anyhow::Result<()> { let TestContext { wallet_contract, wallet_sk, .. } = TestContext::new().await?;